import { useEffect, useRef, useState } from 'react';
import { useSelector } from 'react-redux';
import { Box, CircularProgress, InputAdornment, Link, TextField, Typography } from '@mui/material';
import SearchIcon from '@mui/icons-material/Search';
import { makeStyles } from 'tss-react/mui';

import Dialog from '../Dialog';
import { fetchClasses, resetClasses, selectClasses } from './store';
import { useHostTreeDispatch } from './store/dispatchType';

const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');

const useStyles = makeStyles()(theme => ({
  item: {
    padding: '10px 8px',
    borderBottom: `1px solid ${theme.palette.divider}`,
    color: theme.palette.link.primary,
    cursor: 'pointer',
    wordBreak: 'break-all',
    fontSize: 14,
    '&:hover': {
      background: theme.palette.background.summary,
      textDecoration: 'underline'
    }
  },
  letter: {
    display: 'block',
    padding: '2px 6px',
    textAlign: 'center',
    color: theme.palette.link.primary,
    textDecoration: 'none',
    fontSize: 12,
    lineHeight: 1.4,
    '&:hover': {
      color: theme.palette.primary.main,
      background: theme.palette.background.summary,
      textDecoration: 'none'
    }
  },
  letterSelected: {
    background: `${theme.palette.link.primary} !important`,
    color: `${theme.palette.background.default} !important`,
    borderRadius: 3
  }
}));

interface Props {
  open: boolean;
  onClose: () => void;
  onSelect: (className: string) => void;
}

// Legacy classfinder filter semantics:
// - undefined/null → no filter, server returns all
// - `^[a|A]`-style → alphabet filter (lowercase + uppercase alternation)
// - URI-encoded search term → free-text search
const letterFilter = (letter: string) =>
  encodeURIComponent(`^[${letter.toLowerCase()}|${letter}]`);

export const ClassFinderDialog = ({ open, onClose, onSelect }: Props) => {
  const { classes, cx } = useStyles();
  const dispatch = useHostTreeDispatch();
  const { items, page, hasMore, loading } = useSelector(selectClasses);
  const [selectedLetter, setSelectedLetter] = useState<string | null>(null);
  const [search, setSearch] = useState('');
  const sentinelRef = useRef<HTMLLIElement | null>(null);

  // Active filter: search wins over selected letter.
  const activeFilter = search.trim()
    ? encodeURIComponent(search.trim())
    : selectedLetter
      ? letterFilter(selectedLetter)
      : undefined;

  // Reset + initial load when the dialog opens or filter changes.
  useEffect(() => {
    if (!open) return;
    dispatch(fetchClasses({ page: 1, filter: activeFilter, replace: true }));
  }, [dispatch, open, activeFilter]);

  // Clear class buffer when dialog closes so a future open starts fresh.
  useEffect(() => {
    if (!open) dispatch(resetClasses());
  }, [dispatch, open]);

  // Infinite scroll sentinel.
  useEffect(() => {
    if (!open || !hasMore || loading || page < 1) return;
    const el = sentinelRef.current;
    if (!el) return;
    const observer = new IntersectionObserver(
      entries => {
        for (const entry of entries) {
          if (entry.isIntersecting) {
            dispatch(fetchClasses({ page: page + 1, filter: activeFilter }));
            break;
          }
        }
      },
      { root: null, rootMargin: '200px' }
    );
    observer.observe(el);
    return () => observer.disconnect();
  }, [dispatch, open, hasMore, loading, page, activeFilter]);

  const handleSelect = (cls: string) => {
    onSelect(cls);
    onClose();
  };

  return (
    <Dialog open={open} onClose={onClose} title="Classes" size="lg" fullWidth width="80vw" height="80vh">
      <Box sx={{ mb: 2 }}>
        <TextField
          size="small"
          fullWidth
          placeholder="Search by class (context)"
          value={search}
          onChange={e => {
            setSearch(e.target.value);
            setSelectedLetter(null);
          }}
          slotProps={{
            input: {
              endAdornment: (
                <InputAdornment position="end">
                  <SearchIcon fontSize="small" />
                </InputAdornment>
              )
            }
          }}
        />
      </Box>
      <Box sx={{ display: 'flex', minHeight: 360 }}>
        <Box sx={{ flex: 1, overflowY: 'auto', pr: 1, maxHeight: '60vh' }}>
          {!loading && items.length === 0 && (
            <Typography color="text.secondary" sx={{ p: 2 }}>
              No classes found
            </Typography>
          )}
          <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>
            {items.map((cls, i) => (
              <li
                key={`${cls}-${i}`}
                className={classes.item}
                title={cls}
                onClick={() => handleSelect(cls)}
              >
                {cls}
              </li>
            ))}
            {hasMore && <li ref={sentinelRef} style={{ height: 1 }} aria-hidden />}
          </ul>
          {loading && (
            <Box sx={{ display: 'flex', justifyContent: 'center', py: 2 }}>
              <CircularProgress size={20} />
            </Box>
          )}
        </Box>

        <Box
          component="ul"
          sx={{
            listStyle: 'none',
            padding: 0,
            margin: 0,
            display: 'flex',
            flexDirection: 'column',
            borderLeft: '1px solid #eee',
            pl: 1
          }}
        >
          {ALPHABET.map(letter => (
            <li key={letter}>
              <Link
                component="button"
                underline="none"
                className={cx(
                  classes.letter,
                  selectedLetter === letter && classes.letterSelected
                )}
                onClick={() => {
                  setSearch('');
                  setSelectedLetter(prev => (prev === letter ? null : letter));
                }}
              >
                {letter}
              </Link>
            </li>
          ))}
        </Box>
      </Box>
    </Dialog>
  );
};
