import { useCallback, useEffect, useState } from 'react';
import { Link as RouterLink, useNavigate, useSearchParams } from 'react-router';

import AddIcon from '@mui/icons-material/Add';
import { Alert, Box, Button, Divider, Tab, Tabs, Typography } from '@mui/material';

import { getInventoryVariables } from '../../../store/inventorySlice';
import { selectHasInventory, selectInventoryError, selectInventoryLoaded } from '../../../store/inventorySlice/selectors';
import { Pagination } from '../../common/Pagination';
import Spinner from '../../common/Spinner';
import { useGroupsConfig } from '../GroupsConfigContext';
import { useAppDispatch, useAppSelector } from '../store';
import { setRedirectedToShared } from '../store/groupsListSlice';
import { addNewGroup, changePriority, checkReferences, duplicateGroup, fetchGroups, removeGroup, toggleFavorite } from '../store/groupsListSlice/thunks';
import type { Group, GroupType, ReferencingRule } from '../types';
import { readListParams, storeRowsPerPage } from '../utils/listParams';
import { DuplicateGroupDialog } from './DuplicateGroupDialog';
import { GroupsTable } from './GroupsTable';
import { RemoveGroupDialog } from './RemoveGroupDialog';

interface GroupsListPageProps {
  type: GroupType;
}

export const GroupsListPage = ({ type }: GroupsListPageProps) => {
  const dispatch = useAppDispatch();
  const navigate = useNavigate();
  const [searchParams, setSearchParams] = useSearchParams();
  const { canCreateShared } = useGroupsConfig();

  const { items, total, loading, loaded, error, hasRedirectedToShared } = useAppSelector(state => state.groupsList);
  const hasInventory = useAppSelector(selectHasInventory);
  const inventoryLoaded = useAppSelector(selectInventoryLoaded);
  const inventoryError = useAppSelector(selectInventoryError);

  const [removeTarget, setRemoveTarget] = useState<Group | null>(null);
  const [referencingRules, setReferencingRules] = useState<ReferencingRule[]>([]);
  const [duplicateSource, setDuplicateSource] = useState<Group | null>(null);

  const { page, rowsPerPage, sort } = readListParams(searchParams, type);

  // Depend on the sort fields, not the object identity readListParams rebuilds.
  const { column: sortColumn, descending: sortDescending } = sort;
  const loadGroups = useCallback(
    () => dispatch(fetchGroups({ type, page, rowsPerPage, sort: { column: sortColumn, descending: sortDescending } })),
    [dispatch, type, page, rowsPerPage, sortColumn, sortDescending]
  );

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

  useEffect(() => {
    loadGroups();
  }, [loadGroups]);

  // One-time redirect from an empty personal list to the shared list.
  useEffect(() => {
    if (type === 'personal' && loaded && !error && total === 0 && !hasRedirectedToShared) {
      dispatch(setRedirectedToShared());
      navigate('/shared');
    }
  }, [type, loaded, error, total, hasRedirectedToShared, dispatch, navigate]);

  const updateParams = (updates: Record<string, string>) =>
    setSearchParams(
      previous => {
        const next = new URLSearchParams(previous);
        Object.entries(updates).forEach(([key, value]) => next.set(key, value));
        return next;
      },
      { replace: true }
    );

  const handleSort = (column: string) =>
    updateParams({ sortColumn: column, sortDescending: String(sort.column === column ? !sort.descending : false), page: '1' });

  const handleRowsPerPage = (value: number) => {
    storeRowsPerPage(value);
    updateParams({ perPage: String(value), page: '1' });
  };

  const handleAdd = () => {
    dispatch(addNewGroup(type))
      .unwrap()
      .then(({ id, type: created }) => navigate(`/${created}/${id}`))
      .catch(() => undefined);
  };

  const handleRemove = (group: Group) => {
    setReferencingRules([]);
    setRemoveTarget(group);
    if (group.type === 'shared' || type === 'shared') {
      dispatch(checkReferences(group.id))
        .unwrap()
        .then(setReferencingRules)
        .catch(() => undefined);
    }
  };

  const confirmRemove = () => {
    if (!removeTarget) return;
    const groupType: GroupType = removeTarget.type === 'shared' || type === 'shared' ? 'shared' : 'personal';
    dispatch(removeGroup({ id: removeTarget.id, type: groupType }))
      .unwrap()
      .then(loadGroups)
      .catch(() => undefined);
    setRemoveTarget(null);
  };

  const confirmDuplicate = (targetType: GroupType) => {
    if (!duplicateSource) return;
    const sourceType: GroupType = duplicateSource.type === 'shared' || type === 'shared' ? 'shared' : 'personal';
    dispatch(duplicateGroup({ sourceId: duplicateSource.id, sourceType, targetType }))
      .unwrap()
      .then(({ id, type: created }) => navigate(`/${created}/${id}`))
      .catch(() => undefined);
    setDuplicateSource(null);
  };

  const title = (
    <Typography variant="h1" component="h1" sx={{ mr: 3 }}>
      Groups
    </Typography>
  );

  if (inventoryError) {
    return (
      <Box sx={{ p: 2 }}>
        <Box sx={{ mb: 1 }}>{title}</Box>
        <Alert severity="error">{inventoryError}</Alert>
      </Box>
    );
  }

  if (inventoryLoaded && !hasInventory) {
    return (
      <Box sx={{ p: 2 }}>
        <Box sx={{ mb: 1 }}>{title}</Box>
        <Alert severity="info">
          This application requires reported inventory data. Ensure that you have bootstrapped the hub or check the Health indicator top-right.
        </Alert>
      </Box>
    );
  }

  return (
    <Box sx={{ p: 2 }}>
      <Box sx={{ display: 'flex', alignItems: 'center' }}>
        {title}
        {hasInventory && (
          <Button
            size="small"
            variant="outlined"
            startIcon={<AddIcon />}
            onClick={handleAdd}
            sx={{ color: 'text.primary', borderColor: 'divider', '&:hover': { borderColor: 'text.secondary', backgroundColor: 'action.hover' } }}
          >
            Add
          </Button>
        )}
      </Box>
      <Divider sx={{ mt: 2 }} />

      <Tabs value={type} sx={{ mb: 2, borderBottom: 1, borderColor: 'divider' }}>
        <Tab label="My groups" value="personal" component={RouterLink} to="/" />
        <Tab label="Shared groups" value="shared" component={RouterLink} to="/shared" />
      </Tabs>

      {error ? (
        <Alert severity="error">{error}</Alert>
      ) : loading && items.length === 0 ? (
        <Spinner />
      ) : items.length === 0 ? (
        <Typography align="center" sx={{ mt: 4 }} variant="h6">
          No groups found
        </Typography>
      ) : (
        <>
          <GroupsTable
            type={type}
            groups={items}
            sort={sort}
            total={total}
            onSort={handleSort}
            onToggleFavorite={(group, favorite) => dispatch(toggleFavorite({ id: group.id, type: group.type || type, favorite }))}
            onDuplicate={setDuplicateSource}
            onRemove={handleRemove}
            onChangePriority={(id, priority) =>
              dispatch(changePriority({ id, priority }))
                .unwrap()
                .then(loadGroups)
                .catch(() => undefined)
            }
          />
          <Pagination
            align="left"
            count={total}
            page={page}
            rowsPerPage={rowsPerPage}
            onChangePage={nextPage => updateParams({ page: String(nextPage) })}
            onChangeRowsPerPage={handleRowsPerPage}
          />
        </>
      )}

      <RemoveGroupDialog
        open={removeTarget !== null}
        group={removeTarget}
        isShared={removeTarget?.type === 'shared' || type === 'shared'}
        referencingRules={referencingRules}
        onClose={() => setRemoveTarget(null)}
        onConfirm={confirmRemove}
      />
      {/* Mounted per open so the radio selection always starts from the default. */}
      {duplicateSource && <DuplicateGroupDialog canCreateShared={canCreateShared} onClose={() => setDuplicateSource(null)} onConfirm={confirmDuplicate} />}
    </Box>
  );
};
