import { useEffect, useMemo, useState } from 'react';
import { useSelector } from 'react-redux';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import {
  Box,
  Button,
  CircularProgress,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow
} from '@mui/material';
import { Pagination } from '@northern.tech/common-ui';
import { makeStyles } from 'tss-react/mui';

import ConfirmationDialog from '../common/ConfirmationDialog';
import { useAppDispatch } from './store';
import { resetHostList } from './store/hostsSlice';
import {
  selectCompliance,
  selectComplianceError,
  selectComplianceLoading,
  selectHostList,
  selectHostListLoading,
  selectHostsLoadingStates
} from './store/hostsSlice/selectors';
import {
  deleteHosts,
  fetchHostCompliance,
  fetchHostsByColor
} from './store/hostsSlice/thunks';
import type { HostListEntry } from './types';

const useStyles = makeStyles()(theme => {
  // Pick lighter shades in dark mode so the green/red stays legible against
  // the dark background (the default 700/600 shades are too dark on dark).
  const isDark = theme.palette.mode === 'dark';
  const greenColor = isDark ? theme.palette.green[400] : theme.palette.green[700];
  const redColor = isDark ? theme.palette.red[400] : theme.palette.red[600];
  return ({
  complianceGrid: {
    display: 'grid',
    gridTemplateColumns: '1fr 1fr',
    gap: 24,
    padding: 24,
    background: theme.palette.background.summary,
    borderRadius: 6,
    marginBottom: 12
  },
  complianceCard: {
    display: 'flex',
    flexDirection: 'column',
    gap: 4
  },
  complianceGreen: {
    color: greenColor
  },
  complianceRed: {
    color: redColor
  },
  complianceCount: {
    fontSize: 32,
    fontWeight: 600,
    lineHeight: 1,
    color: 'inherit'
  },
  compliancePercent: {
    fontSize: 20,
    fontWeight: 600,
    color: 'inherit'
  },
  complianceText: {
    color: theme.palette.text.primary,
    margin: '4px 0 0 0'
  },
  complianceShowLink: {
    color: theme.palette.link.primary,
    textDecoration: 'none',
    fontSize: 14,
    marginTop: 8,
    display: 'inline-block',
    '&:hover': {
      textDecoration: 'underline'
    }
  },
  complianceCaption: {
    color: theme.palette.text.muted,
    fontSize: 13,
    fontStyle: 'italic',
    margin: 0
  }
});
});

// Row payloads are normalized to `{hostkey, hostname?}` by the thunks, so
// direct field access is safe here.
const getHostkey = (row: HostListEntry): string => row.hostkey ?? '';
const getHostname = (row: HostListEntry): string => row.hostname ?? '';

const calcPercent = (count: number, total: number): number => {
  if (!total || !count) return 0;
  return Math.round((count / total) * 100);
};

type ColorFilter = 'green' | 'red' | null;

const COLOR_HEADING: Record<'green' | 'red', string> = {
  green: 'Fully compliant hosts',
  red: 'Hosts with less than 100% compliance'
};

const DEFAULT_ROWS_PER_PAGE = 10;

export const LabelHostListPage = () => {
  const { classes, cx } = useStyles();
  const { label } = useParams<{ label: string }>();
  const [searchParams] = useSearchParams();
  const navigate = useNavigate();
  const dispatch = useAppDispatch();

  const compliance = useSelector(selectCompliance);
  const complianceLoading = useSelector(selectComplianceLoading);
  const complianceError = useSelector(selectComplianceError);
  const hostList = useSelector(selectHostList);
  const hostsLoading = useSelector(selectHostListLoading);
  const { deleteHosts: removing } = useSelector(selectHostsLoadingStates);

  const includes = useMemo(() => {
    const raw = searchParams.get('inc');
    // `inc=` (empty string) is an explicit "no class filter" signal sent by
    // the tree's All-hosts click — return [] instead of falling back to the
    // label name. Only fall back when `inc` is absent.
    if (raw !== null) return raw.split(',').filter(Boolean);
    return label ? [label.toLowerCase()] : [];
  }, [searchParams, label]);

  const excludes = useMemo(() => {
    const raw = searchParams.get('exc');
    if (raw) return [raw];
    return [];
  }, [searchParams]);

  const includesKey = includes.join(',');
  const excludesKey = excludes.join('|');

  const [colorFilter, setColorFilter] = useState<ColorFilter>(null);
  const [selectedHostkeys, setSelectedHostkeys] = useState<Set<string>>(new Set());
  const [page, setPage] = useState(1);
  const [rowsPerPage, setRowsPerPage] = useState(DEFAULT_ROWS_PER_PAGE);
  const [removeOpen, setRemoveOpen] = useState(false);

  // Refetch compliance whenever context changes; reset stale host list too.
  useEffect(() => {
    dispatch(fetchHostCompliance({ includes, excludes }));
    dispatch(resetHostList());
    setColorFilter(null);
    setSelectedHostkeys(new Set());
    setPage(1);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [dispatch, includesKey, excludesKey]);

  const handleShowHosts = (color: 'green' | 'red') => {
    setColorFilter(color);
    setSelectedHostkeys(new Set());
    setPage(1);
    dispatch(fetchHostsByColor({ color, includes, excludes }));
  };

  const total = compliance?.total ?? 0;
  const greenCount = compliance?.green ?? 0;
  const redCount = compliance?.red ?? 0;

  const pageRows = useMemo(() => {
    if (!hostList) return [];
    const start = (page - 1) * rowsPerPage;
    return hostList.slice(start, start + rowsPerPage);
  }, [hostList, page, rowsPerPage]);

  const pageSelectionKeys = pageRows.map((r, idx) => {
    const hostkey = getHostkey(r);
    return hostkey || `__row_${idx}__${getHostname(r)}`;
  });

  const allCurrentSelected =
    pageSelectionKeys.length > 0 && pageSelectionKeys.every(k => selectedHostkeys.has(k));

  const toggleSelectAll = () => {
    setSelectedHostkeys(prev => {
      const next = new Set(prev);
      if (allCurrentSelected) pageSelectionKeys.forEach(k => next.delete(k));
      else pageSelectionKeys.forEach(k => next.add(k));
      return next;
    });
  };

  const toggleSelectOne = (k: string) => {
    setSelectedHostkeys(prev => {
      const next = new Set(prev);
      if (next.has(k)) next.delete(k);
      else next.add(k);
      return next;
    });
  };

  const confirmRemove = async () => {
    const realHostkeys = [...selectedHostkeys].filter(k => !k.startsWith('__row_'));
    if (realHostkeys.length === 0) {
      setRemoveOpen(false);
      return;
    }
    const action = await dispatch(deleteHosts(realHostkeys));
    // Keep the dialog open and the selection intact on failure so the user can
    // retry; the thunk already surfaces the error via notify.
    if (!deleteHosts.fulfilled.match(action)) return;
    // Refresh compliance after deletion so the counts update.
    dispatch(fetchHostCompliance({ includes, excludes }));
    setSelectedHostkeys(new Set());
    setRemoveOpen(false);
  };

  return (
    <div>
      <div className="pageTitle">
        <h1 className="astrolabeLocation">
          <span>All hosts</span>{' '}
          <span style={{ margin: '0 8px' }}>»</span>{' '}
          <span>{label}</span>{' '}
          <span style={{ color: '#888', fontWeight: 400 }}>({total || '…'})</span>
        </h1>
      </div>

      {complianceError && <div className="alert alert-error">{complianceError}</div>}

      {compliance === null && complianceLoading ? (
        <div style={{ display: 'flex', justifyContent: 'center', padding: 40 }}>
          <CircularProgress size={28} />
        </div>
      ) : compliance !== null ? (
        <div className={classes.complianceGrid}>
          <div className={cx(classes.complianceCard, classes.complianceGreen)}>
            <div className={classes.complianceCount}>{greenCount}</div>
            <div className={classes.compliancePercent}>({calcPercent(greenCount, total)}%)</div>
            <p className={classes.complianceText}>Hosts with 100% compliance.</p>
            {greenCount > 0 && (
              <a
                href="#"
                className={classes.complianceShowLink}
                onClick={e => {
                  e.preventDefault();
                  handleShowHosts('green');
                }}
              >
                Show hosts
              </a>
            )}
          </div>

          <div className={cx(classes.complianceCard, classes.complianceRed)}>
            <div className={classes.complianceCount}>{redCount}</div>
            <div className={classes.compliancePercent}>({calcPercent(redCount, total)}%)</div>
            <p className={classes.complianceText}>Hosts with less than 100% compliance.</p>
            {redCount > 0 && (
              <a
                href="#"
                className={classes.complianceShowLink}
                onClick={e => {
                  e.preventDefault();
                  handleShowHosts('red');
                }}
              >
                Show hosts
              </a>
            )}
          </div>
        </div>
      ) : null}

      <p className={classes.complianceCaption}>
        Total CFEngine compliance level for all hosts during the last reported run.
      </p>

      {colorFilter !== null && (
        <div style={{ marginTop: 24 }}>
          <h4>{COLOR_HEADING[colorFilter]}</h4>

          {hostsLoading ? (
            <div style={{ display: 'flex', justifyContent: 'center', padding: 24 }}>
              <CircularProgress size={24} />
            </div>
          ) : hostList && hostList.length > 0 ? (
            <>
              <TableContainer>
                <Table size="small">
                  <TableHead>
                    <TableRow>
                      <TableCell padding="checkbox">
                        <input
                          type="checkbox"
                          checked={allCurrentSelected}
                          ref={el => {
                            if (el) {
                              el.indeterminate =
                                !allCurrentSelected && selectedHostkeys.size > 0;
                            }
                          }}
                          onChange={toggleSelectAll}
                        />
                      </TableCell>
                      <TableCell>Host</TableCell>
                    </TableRow>
                  </TableHead>
                  <TableBody>
                    {pageRows.map((row, idx) => {
                      const hostkey = getHostkey(row);
                      const hostname = getHostname(row);
                      const selectionKey = hostkey || `__row_${idx}__${hostname}`;
                      const checked = selectedHostkeys.has(selectionKey);
                      return (
                        <TableRow key={selectionKey} hover>
                          <TableCell padding="checkbox">
                            <input
                              type="checkbox"
                              checked={checked}
                              onChange={() => toggleSelectOne(selectionKey)}
                            />
                          </TableCell>
                          <TableCell>
                            <a
                              href="#"
                              className="btn-blue-link"
                              onClick={e => {
                                e.preventDefault();
                                if (hostkey) navigate(`/${hostkey}`);
                              }}
                            >
                              {hostname || hostkey || '—'}
                            </a>
                          </TableCell>
                        </TableRow>
                      );
                    })}
                  </TableBody>
                </Table>
              </TableContainer>

              <Box sx={{ display: 'flex', alignItems: 'center', mt: 1 }}>
                <Button
                  variant="outlined"
                  color="error"
                  disabled={selectedHostkeys.size === 0 || removing}
                  onClick={() => setRemoveOpen(true)}
                >
                  Remove selected hosts
                </Button>
                <Pagination
                  count={hostList.length}
                  rowsPerPage={rowsPerPage}
                  page={page}
                  onChangePage={setPage}
                  onChangeRowsPerPage={(value: number) => {
                    setRowsPerPage(value);
                    setPage(1);
                  }}
                />
              </Box>
            </>
          ) : (
            <div className="alert alert-info">No hosts found.</div>
          )}
        </div>
      )}

      <ConfirmationDialog
        open={removeOpen}
        onClose={() => setRemoveOpen(false)}
        onConfirm={confirmRemove}
        title={selectedHostkeys.size > 1 ? 'Remove hosts?' : 'Remove host?'}
        message="Are you sure you want to remove the selected host(s)? Deletion is permanent. Please ensure the host no longer exists or CFEngine is fully uninstalled from it. After deletion, if you want the host to report again, you will need to generate a new keypair and bootstrap again, as if it was a completely new host, it will not reappear automatically."
        confirmText="Remove"
        confirmColor="error"
        cancelText="Cancel"
      />
    </div>
  );
};
