/* eslint-disable react/prop-types */
import React, { useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { AddRounded, ExpandMoreRounded, FilterAltRounded, SearchRounded } from '@mui/icons-material';
import PeopleIcon from '@mui/icons-material/People';
import PeopleOutlineIcon from '@mui/icons-material/PeopleOutline';

import {
  ALL,
  CATEGORY_OPTIONS,
  DISABLED,
  ENABLED,
  IMAGE_OPTIONS,
  LUMINOUSX,
  NEW_ROW_ID,
  NOT_APPROVED,
  SELECT_STATUS_OPTIONS,
  STATUS_ALL,
  STATUS_BRANDS,
  STATUS_CELL_RENDER,
  STATUS_OPTIONS,
  STATUS_PEOPLE,
  X_RAY_OPTIONS,
  X_RAY_SELECT_OPTIONS,
} from '../constants';
import { SORT_ASC } from '@/modules/@common/constants/sort';

import * as entitiesSelectors from '../redux/selectors';
import {
  createEntityAction,
  getAccountOptionsAction,
  getDataAction,
  getLanguages,
  setAction,
  setTableAction,
  updateEntityAction,
} from '../redux/slices';
import { getIAB } from '@/modules/@common/iab/helpers';
import { omitUndefinedProps } from '@/mui/helpers';
import { createFlatTreeMap } from '@/mui/helpers/treeView';

import IabSelector from '@/modules/@common/iab/components/IabSelector/IabSelector';
import CommonList from '@/modules/@common/List';
import AliasDialog from './AliasDialog';
import AvatarEdit from './AvatarEdit';
import MergeEntitiesDialog from './MergeEntitiesDialog';
import {
  Autocomplete,
  Button,
  Chip,
  DataGridPro,
  Divider,
  IconButton,
  InputAdornment,
  Menu,
  MenuItem,
  Stack,
  TextField,
  Tooltip,
  Typography,
  UserAvatar,
} from '@/mui/components';
import DateCell from '@/mui/components/DataGridPro/components/DateCell/View';
import DateTimeCell from '@/mui/components/DataGridPro/components/DateTimeCell/View';

import styles from './Entities.module.scss';

function Entities() {
  const [flatTree] = useState(
    createFlatTreeMap(
      getIAB(),
      {
        label: 'name',
        children: 'categories',
      },
      [],
    ),
  );
  const [addEntityAnchorEl, setAddEntityAnchorEl] = useState(null);
  const [rowAliasDialog, setRowAliasDialog] = useState(false);
  const [selectedRows, setSelectedRows] = React.useState([]);
  const [actions, setActions] = useState(null);
  const [mergeEntitiesDialog, setMergeEntitiesDialog] = useState(false);

  const dispatch = useDispatch();

  const data = useSelector(entitiesSelectors.dataSelector);
  const page = useSelector(entitiesSelectors.pageSelector);
  const pageSize = useSelector(entitiesSelectors.pageSizeSelector);
  const totalCount = useSelector(entitiesSelectors.totalCountSelector);
  const sortBy = useSelector(entitiesSelectors.sortBySelector);
  const sortOrder = useSelector(entitiesSelectors.sortOrderSelector);

  const search = useSelector(entitiesSelectors.searchSelector);
  const category = useSelector(entitiesSelectors.categorySelector);
  const xrayStatus = useSelector(entitiesSelectors.xrayStatusSelector);
  const tagStatus = useSelector(entitiesSelectors.tagStatusSelector);
  const image = useSelector(entitiesSelectors.imageSelector);
  const accountOptions = useSelector(entitiesSelectors.accountOptionsSelector);
  const languages = useSelector(entitiesSelectors.languagesSelector);

  const sortModel = useMemo(() => [{ field: sortBy, sort: sortOrder }], [sortBy, sortOrder]);

  const getMergeEntitiesIsActive = () => {
    const entities = data ? data.filter((d) => selectedRows?.includes(d.id)) : [];

    if (entities.length < 2) return false;

    const firstCategory = entities[0].category;
    const firstAccount = entities[0].account ? entities[0].account.id : null;

    for (let i = 1; i < entities.length; i++) {
      const entity = entities[i];

      if (entity.category !== firstCategory) {
        return false;
      }

      const entityAccount = entity.account ? entity.account.id : null;
      if (entityAccount !== firstAccount) {
        return false;
      }
    }

    return true;
  };

  const handleFilter = (filter) => {
    const { sortBy: sortBy$, sortOrder: sortOrder$, page: page$, pageSize: pageSize$, ...mainState } = filter;

    dispatch(
      setTableAction(
        omitUndefinedProps({
          sortBy: sortBy$,
          sortOrder: sortOrder$,
          page: page$,
          pageSize: pageSize$,
          selected: [],
        }),
      ),
    );

    dispatch(
      setAction({
        ...mainState,
      }),
    );
    dispatch(getDataAction());
  };

  const handleSorting = ([sort]) => {
    if (!sort) {
      handleFilter({ sortBy, sortOrder: SORT_ASC });
      return;
    }

    handleFilter({ sortBy: sort.field, sortOrder: sort.sort });
  };

  useEffect(() => {
    dispatch(getDataAction());
    dispatch(getLanguages());
  }, []);

  const handleRowUpdate = (row, oldRow) => {
    const tempRow = window.structuredClone(row);

    // If the row is not changed, return the row
    if (JSON.stringify(tempRow) === JSON.stringify(oldRow)) return tempRow;

    if (oldRow && oldRow.value !== row.value) {
      const englishIndex = row.keywords.findIndex((keyword) => keyword.lang === 'EN');

      tempRow.keywords[englishIndex].value = row.value;
    }

    if (row.birthDate) {
      tempRow.metaData = { ...tempRow.metaData, birthDate: row.birthDate };
    }

    if (row.iab) {
      tempRow.metaData = { ...tempRow.metaData, iab: row.iab };
    }

    if (row.types) {
      if (Array.isArray(row.types)) {
        tempRow.types = row.types;
      } else {
        const option = X_RAY_SELECT_OPTIONS.find((option$) => option$.value === row.types);
        tempRow.types = option ? option.types : [];
      }
    } else {
      tempRow.types = [];
    }

    tempRow.status = typeof row.status === 'string' ? row.status : row.status.value;

    const hasLuminousX = row.types && row.types.includes(LUMINOUSX);
    const isXrayEnabled = row.types === ENABLED || hasLuminousX;

    if (!isXrayEnabled) {
      tempRow.types = X_RAY_SELECT_OPTIONS.find((option) => option.value === DISABLED)?.types;
    }

    if (row.id === NEW_ROW_ID) return tempRow;

    dispatch(updateEntityAction(tempRow));
    return tempRow;
  };

  const handleAddNewRow = (type) => {
    if (data.some((row) => row.id === NEW_ROW_ID)) return;

    if (category !== type) {
      handleFilter({ category: type, page: 0 });
    }

    const newRow = {
      category: type,
      id: NEW_ROW_ID,
      status: NOT_APPROVED,
      value: `New Entity - ${Date.now()}`,
      keywords: [
        {
          lang: 'EN',
          value: `New Entity - ${Date.now()}`,
          suggestions: null,
        },
      ],
    };

    dispatch(createEntityAction(newRow));
    setAddEntityAnchorEl(null);
  };

  return (
    <CommonList
      title="Entities"
      renderFilters={
        <Stack direction="row" alignItems="center" spacing={2} fullWidth>
          <Button
            size="small"
            color="neutral"
            variant="outlined"
            disabled={!getMergeEntitiesIsActive()}
            endIcon={<ExpandMoreRounded />}
            onClick={(event) => setActions(event.currentTarget)}
          >
            Actions
          </Button>
          {actions && (
            <Menu open anchorEl={actions} onClose={() => setActions(null)}>
              <MenuItem
                onClick={() => {
                  setMergeEntitiesDialog(true);
                  setActions('');
                }}
              >
                Merge Entities
              </MenuItem>
            </Menu>
          )}
          <div>
            <TextField
              className={styles.SearchField}
              size="small"
              placeholder="Search"
              value={search}
              variant="outlined"
              onChange={({ target }) => handleFilter({ search: target.value, page: 0 })}
              inputProps={{ autoComplete: 'off' }}
              InputProps={{
                endAdornment: (
                  <InputAdornment position="end">
                    <IconButton onClick={() => null}>
                      <SearchRounded />
                    </IconButton>
                  </InputAdornment>
                ),
              }}
            />
          </div>

          <Stack spacing={1} direction="row" alignItems="center">
            <Divider orientation="vertical" flexItem />
            <FilterAltRounded color="shades.900" fontSize="medium" />
          </Stack>
          <Autocomplete
            className={styles.TypeSelect}
            value={CATEGORY_OPTIONS.find((s) => s.value === category) ?? STATUS_ALL}
            options={CATEGORY_OPTIONS}
            size="small"
            onChange={(e, selected$) => handleFilter({ category: selected$?.value ?? STATUS_ALL, page: 0 })}
            renderInput={(params) => <TextField {...params} placeholder="Type" />}
          />
          <Autocomplete
            className={styles.AccountSelect}
            options={accountOptions || []}
            loading={!accountOptions}
            size="small"
            onChange={(e, selectedAccount) => handleFilter({ account: selectedAccount, page: 0 })}
            onOpen={() => {
              dispatch(setAction({ accountOptions: [] }));
              dispatch(getAccountOptionsAction(''));
            }}
            onInputChange={(e, searchText) => dispatch(getAccountOptionsAction(searchText))}
            renderInput={(params) => (
              <TextField {...params} data-id="site" value="" variant="outlined" placeholder="Account" />
            )}
          />
          <Autocomplete
            className={styles.XrayStatus}
            value={X_RAY_OPTIONS.find((s) => s.value === xrayStatus) ?? null}
            options={X_RAY_OPTIONS}
            size="small"
            onChange={(e, selected$) => handleFilter({ xrayStatus: selected$?.value ?? ALL, page: 0 })}
            renderInput={(params) => <TextField {...params} placeholder="X-Ray Status" />}
            disabled={tagStatus === DISABLED}
          />
          <Autocomplete
            className={styles.TagStatus}
            value={STATUS_OPTIONS.find((s) => s.value === tagStatus) ?? null}
            options={STATUS_OPTIONS}
            size="small"
            onChange={(e, selected$) => handleFilter({ tagStatus: selected$?.value ?? ALL, page: 0 })}
            renderInput={(params) => <TextField {...params} placeholder="Tag Status" />}
          />
          <Autocomplete
            className={styles.ImageFilter}
            value={IMAGE_OPTIONS.find((s) => s.value === image) ?? null}
            options={IMAGE_OPTIONS}
            size="small"
            onChange={(e, selected$) => handleFilter({ image: selected$?.value ?? ALL, page: 0 })}
            renderInput={(params) => <TextField {...params} placeholder="Image" />}
          />
        </Stack>
      }
      renderActions={
        <Stack direction="row">
          <Tooltip title="Add Entity">
            <Button
              size="small"
              variant="contained"
              color="primary"
              data-id="new"
              startIcon={<AddRounded />}
              onClick={(event) => setAddEntityAnchorEl(event.currentTarget)}
            >
              Entity
            </Button>
          </Tooltip>
          <Menu
            anchorEl={addEntityAnchorEl}
            open={Boolean(addEntityAnchorEl)}
            onClose={() => setAddEntityAnchorEl(null)}
          >
            <MenuItem onClick={() => handleAddNewRow(STATUS_PEOPLE)}>Person</MenuItem>
            <MenuItem onClick={() => handleAddNewRow(STATUS_BRANDS)}>Brand</MenuItem>
          </Menu>
        </Stack>
      }
    >
      <DataGridPro
        pagination
        autoHeight
        size="large"
        checkboxSelection
        disableRowSelectionOnClick
        paginationMode="server"
        sortingMode="server"
        rowsPerPageOptions={[10, 15, 25]}
        rowCount={totalCount}
        paginationModel={{ page, pageSize }}
        sortModel={sortModel}
        processRowUpdate={handleRowUpdate}
        onSortModelChange={handleSorting}
        onPaginationModelChange={handleFilter}
        onRowSelectionModelChange={({ ids = [] }) => {
          setSelectedRows([...ids]);
        }}
        rows={data || []}
        columns={[
          {
            field: 'thumbnailFileUrl',
            headerName: 'Image',
            headerAlign: 'center',
            width: 60,
            align: 'center',
            sortable: false,
            filterable: false,
            disableColumnMenu: true,
            editable: true,
            renderEditCell: (props) => (
              <AvatarEdit
                {...props}
                overrideProps={{
                  root: {
                    accept: 'image/*',
                  },
                }}
              />
            ),
            renderCellValue: (params) => {
              const [firstName = '', lastName = ''] = params.row.value?.trim().split(/\s+/) || [];

              return (
                <UserAvatar
                  className={styles.Avatar}
                  size="large"
                  src={params.value}
                  alt={params.row.value}
                  id={params.id}
                  firstName={firstName}
                  lastName={lastName}
                />
              );
            },
          },
          {
            field: 'value',
            headerAlign: 'start',
            headerName: 'Name',
            cellType: 'string',
            editable: true,
            disableColumnMenu: true,
            width: 180,
            renderCellValue: (params) => (
              <Tooltip title={`ID: ${params.row.id}`}>
                <span>{params.value}</span>
              </Tooltip>
            ),
          },
          {
            field: 'iab',
            headerName: 'IAB Category',
            cellType: 'multiSelect',
            width: 160,
            disableColumnMenu: true,
            editable: true,
            sortable: false,
            renderCellValue: (props) =>
              !props.row.metaData?.iab?.length ? (
                'No Tags'
              ) : (
                <Stack spacing={2} alignItems="center" direction="row" justifyContent="flex-start">
                  {props.row.metaData.iab.map((nodeId) => {
                    const { label } = flatTree.get(nodeId);

                    return <Chip key={nodeId} size="small" label={label} color="neutral" />;
                  })}
                </Stack>
              ),
            renderEditCell: (props) => (
              <IabSelector
                {...props}
                autoFocus
                placeholder="Select IAB tag"
                value={props.value || props.row?.metaData?.iab || []}
                size={props.size}
                onChange={(event, value) => {
                  props.onChange(value.map(({ id }) => id));
                }}
              />
            ),
          },
          {
            field: 'status',
            headerName: 'Tag Status',
            cellType: 'autocompleteSelect',
            width: 130,
            disableColumnMenu: true,
            editable: true,
            valueOptions: SELECT_STATUS_OPTIONS,
            renderCellValue: (params) => (
              <Typography variant="body2" color={STATUS_CELL_RENDER[params.row.status]?.color}>
                {STATUS_CELL_RENDER[params.row.status]?.label}
              </Typography>
            ),
          },
          {
            field: 'types',
            headerName: 'X-Ray Status',
            width: 130,
            cellType: 'singleSelect',
            disableColumnMenu: true,
            editable: true,
            sortable: false,
            valueOptions: X_RAY_SELECT_OPTIONS,
            renderCellValue: (params) => (
              <Typography
                variant="body2"
                color={
                  STATUS_CELL_RENDER[
                    params.value?.includes(LUMINOUSX) && params.row.status !== DISABLED ? ENABLED : DISABLED
                  ]?.color
                }
              >
                {params.value?.includes(LUMINOUSX) ? 'Enabled' : 'Disabled'}
              </Typography>
            ),
            renderEditProps: (params) => {
              let { value } = params;
              if (Array.isArray(params.value)) {
                value = params.value?.includes(LUMINOUSX) ? ENABLED : DISABLED;
              }

              return {
                root: {
                  value,
                  disabled: [DISABLED].includes(params.row.status),
                },
              };
            },
          },
          {
            field: 'account',
            headerName: 'Account',
            width: 140,
            disableColumnMenu: true,
            editable: false,
            sortable: false,
            renderCellValue: (params) => (
              <Tooltip title={params.value?.name}>
                <Typography className={styles.AccountCell} variant="body2">
                  {params.value?.name || ''}
                </Typography>
              </Tooltip>
            ),
          },
          {
            field: 'birthDate',
            headerName: 'Birthday',
            headerAlign: 'start',
            disableColumnMenu: true,
            width: 130,
            cellType: 'date',
            sortable: false,
            editable: category === STATUS_PEOPLE,
            renderEditProps: (params) => ({
              root: {
                value: params.row.metaData?.birthDate || new Date(1980, 0, 1),
                minDate: new Date(100, 1, 1),
              },
            }),
            renderCellValue: (params) =>
              params.row?.metaData?.birthDate && params.row.category === STATUS_PEOPLE ? (
                <DateCell value={params.row.metaData?.birthDate} />
              ) : (
                ''
              ),
          },
          {
            field: 'counterVideos',
            headerName: 'Videos',
            width: 90,
            cellType: 'number',
            disableColumnMenu: true,
            editable: false,
          },
          {
            field: 'playCount',
            cellType: 'number',
            headerName: 'Views',
            renderHeader: (params) => (
              <Tooltip title="Video views in the last 30 days">
                <span className={styles.RenderHeaderTitle}>{params.colDef.headerName}</span>
              </Tooltip>
            ),
            width: 90,
            disableColumnMenu: true,
            editable: false,
          },
          {
            field: 'created',
            headerName: 'Created',
            width: 190,
            disableColumnMenu: true,
            cellType: 'dateTime',
            editable: false,
          },
          {
            field: 'updated',
            headerName: 'Updated',
            width: 190,
            disableColumnMenu: true,
            editable: false,
            cellType: 'dateTime',
            renderCellValue: (params) =>
              params.value ? (
                <Tooltip title={`Updated By: ${params.row.refUserId || 'Unknown'}`}>
                  <DateTimeCell value={params.value} />
                </Tooltip>
              ) : (
                <div />
              ),
          },
          {
            field: 'source',
            editable: false,
            disableColumnMenu: true,
            headerName: 'Image Source',
            width: 120,
          },
          {
            editable: false,
            field: 'keywords',
            disableColumnMenu: true,
            sortable: false,
            align: 'center',
            headerName: 'Alias',
            cellType: 'actions',
            width: 60,
            renderCellValue: (params) => {
              const hasAlias = params.value?.length > 1 || params.value[0]?.suggestions?.length;

              return (
                <Stack fullWidth>
                  <IconButton onClick={() => setRowAliasDialog(params.row)}>
                    {hasAlias ? <PeopleIcon /> : <PeopleOutlineIcon />}
                  </IconButton>
                </Stack>
              );
            },
          },
        ]}
      />
      {rowAliasDialog && (
        <AliasDialog
          handleRowUpdate={handleRowUpdate}
          handleClose={() => setRowAliasDialog(null)}
          row={rowAliasDialog}
          languages={languages}
        />
      )}

      {mergeEntitiesDialog && (
        <MergeEntitiesDialog
          open={mergeEntitiesDialog}
          selectedRows={selectedRows}
          onClose={() => setMergeEntitiesDialog(false)}
        />
      )}
    </CommonList>
  );
}

export default Entities;
