import React, { useContext, useMemo, useState, useEffect } from 'react';
import Button from '@mui/material/Button';
import Dialog from '@mui/material/Dialog';
import DialogContent from '@mui/material/DialogContent';
import FormControl from '@mui/material/FormControl';
import InputLabel from '@mui/material/InputLabel';
import NativeSelect from '@mui/material/NativeSelect';
import Collapse from '@mui/material/Collapse';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import MuiLink from '@mui/material/Link';
import Autocomplete from '@mui/material/Autocomplete';
import TextField from '@mui/material/TextField';
import RadioGroup from '@mui/material/RadioGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import Radio from '@mui/material/Radio';
import { Trans } from '@lingui/macro';
import { AvailableDashboardsContext } from '../AvailableDashboardProvider';
import { Dash, NewDash, OnChangeProps } from './useSaveDialog';
import CreateListDialog from './CreateListDialog';
import BuildIcon from '@mui/icons-material/Build';

interface SettingDialogBase {
  openDialogButton: React.ReactElement | null;
  isOpen: boolean;
  dashboard: NewDash | Dash;
  closeDialog: () => void;
  onChange: (v: OnChangeProps) => (e: any) => void;
  onChangeDash: (e: any) => void;
}
interface NewSettingDialogProps extends SettingDialogBase {
  create: () => void;
}
interface UpdateSettingDialogProps extends SettingDialogBase {
  update: () => void;
  remove: () => void;
}
type SettingDialogProps = NewSettingDialogProps | UpdateSettingDialogProps;

const SelectForm: React.FC<React.ComponentProps<typeof NativeSelect> & { label: React.ReactNode }> = (props) => (
  <DialogContent>
    <FormControl fullWidth>
      <InputLabel>{props.label}</InputLabel>
      <NativeSelect {...props} />
    </FormControl>
  </DialogContent>
);

// Konfig-URL
const getConfigUrl = (type?: string, id?: string | number) => {
  if (!type || !id) return '#';
  if (type === 'dash') return `/config/GRP${id}`;
  if (type === 'map') return `/config/map/${id}`;
  return '#';
};

/** --- Tree / Bereiche laden (GRP->BER) --- */
type JsTreeNode = { id: string; text: string; children: boolean; type?: string };
type FolderGroup = { id: string; label: string; items: { id: string | number; label: string }[] };

type BoardOption = {
  label: string;
  value: string;
  group: string;
  subtitle?: string;
};

type AreaOption = {
  label: string;
  value: string;
  group: string;
};

type SourceMode = 'existing' | 'map';

const fetchChildren = async (nodeId: string): Promise<JsTreeNode[]> => {
  const url = nodeId === '#' ? '/TreeREP' : `/TreeSTTNode/${encodeURIComponent(nodeId)}`;
  const res = await fetch(url, { headers: { Accept: 'application/json' } });
  if (!res.ok) throw new Error(`Tree fetch failed: ${res.status}`);
  return (await res.json()) as JsTreeNode[];
};

const typeFromNodeId = (id?: string) => (id ?? '').substring(3, 6);
const getNodeType = (n: JsTreeNode) => n.type ?? typeFromNodeId(n.id);

const extractNumericId = (jsTreeId: string | number): number => {
  if (typeof jsTreeId === 'number') return jsTreeId;
  const m = String(jsTreeId).match(/(\d+)/);
  return m ? Number(m[1]) : Number(jsTreeId);
};

const collectAreaGroups = async (): Promise<FolderGroup[]> => {
  const root = await fetchChildren('#');
  const groups = root.filter(n => (n.type ?? typeFromNodeId(n.id)) === 'GRP');

  if (groups.length > 0) {
    const results = await Promise.all(
      groups.map(async (g) => {
        const kids = await fetchChildren(g.id);
        const areas = kids.filter(n => (n.type ?? typeFromNodeId(n.id)) === 'BER' || n.children === false);
        return {
          id: g.id,
          label: g.text,
          items: areas.map(a => ({ id: a.id, label: a.text })),
        } as FolderGroup;
      })
    );
    results.sort((a, b) => a.label.localeCompare(b.label));
    results.forEach(g => g.items.sort((a, b) => String(a.label).localeCompare(String(b.label))));
    return results;
  }

  // Fallback: Root hat direkt Bereiche
  const rootAreas = root.filter(n => (n.type ?? typeFromNodeId(n.id)) === 'BER' || n.children === false || !n.children);
  if (rootAreas.length > 0) {
    return [{
      id: '__areas__',
      label: 'Bereiche',
      items: rootAreas.map(a => ({ id: a.id, label: a.text }))
                      .sort((a, b) => a.label.localeCompare(b.label)),
    }];
  }
  return [];
};
/** --------------------------------------- */

const SettingDialog: React.FC<SettingDialogProps> = (props) => {
  const {
    openDialogButton,
    isOpen,
    dashboard,
    closeDialog,
    onChange,
    onChangeDash,
  } = props;

  const createOrUpdate =
    (props as UpdateSettingDialogProps).update ||
    (props as NewSettingDialogProps).create;

  const isCreate = (props as NewSettingDialogProps).create != null;

  // Context
  const dashboardsCtx = useContext(AvailableDashboardsContext);
  const dashList = dashboardsCtx?.dashList ?? [];
  const iframeList = dashboardsCtx?.iframeList ?? [];
  const taskoNews = dashboardsCtx?.taskoNews ?? [];
  const createList = dashboardsCtx?.createList;
  const authPermissions = ((window as any)?.store?.getState?.()?.auth ??
    {}) as Partial<{ showMap?: boolean }>;
  const globalPermissions = ((window as any)?.userAuth ??
    {}) as Partial<{ showMap?: boolean }>;
  const canUseMap = Boolean(
    authPermissions?.showMap ?? globalPermissions?.showMap,
  );

  const [showAdvanced, setShowAdvanced] = useState(false);
  const [bereichFilter, setBereichFilter] = useState<string>('ALL');
  const [typFilter, setTypFilter] = useState<string>('ALL');
  const [createOwnOpen, setCreateOwnOpen] = useState(false);
  const [sourceMode, setSourceMode] = useState<SourceMode>('existing');

  // Bereiche für Map-Card-Auswahl
  const [areaGroups, setAreaGroups] = useState<FolderGroup[]>([]);
  const [areasLoading, setAreasLoading] = useState(false);
  const [areasError, setAreasError] = useState<string>('');

  useEffect(() => {
    // Bereiche laden, sobald Dialog geöffnet ist
    if (!isOpen || !canUseMap) return;
    let cancelled = false;
    (async () => {
      setAreasLoading(true);
      setAreasError('');
      try {
        const groups = await collectAreaGroups();
        if (!cancelled) setAreaGroups(groups);
      } catch (e) {
        if (!cancelled) setAreasError('Bereiche konnten nicht geladen werden.');
      } finally {
        if (!cancelled) setAreasLoading(false);
      }
    })();
    return () => { cancelled = true; };
  }, [isOpen, canUseMap]);

  // Defaults beim Öffnen
  useEffect(() => {
    if (!isOpen) return;
    if ((dashboard as any).refreshMinutes == null) {
      onChange('refreshMinutes')({ target: { value: 30 } });
    }
    if ((dashboard as any).count == null) {
      onChange('count')({ target: { value: 100 } });
    }
    setShowAdvanced(false);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isOpen]);

  useEffect(() => {
    if (!isOpen) return;
    const wantsMap = (dashboard as any).type === 'map';
    setSourceMode(wantsMap && canUseMap ? 'map' : 'existing');
  }, [isOpen, dashboard, canUseMap]);

  const unique = <T, K extends keyof T>(arr: T[], key: K) =>
    Array.from(new Set(arr.map((x) => String(x[key] ?? ''))))
      .filter(Boolean)
      .sort((a, b) => a.localeCompare(b));

  const bereiche = useMemo(() => unique(dashList, 'ber_name'), [dashList]);
  
  // Wird im CreateListDialog genutzt
  const typen = useMemo(() => {
    const base = unique(dashList, 'listen_typ');
    const merged = base.includes('Info') ? base : [...base, 'Info'];
    return merged.sort((a, b) => a.localeCompare(b));
  }, [dashList]);

  // Filter anwenden
  const filteredDashList = useMemo(() => {
    return dashList.filter(
      (d) =>
        (bereichFilter === 'ALL' || d.ber_name === bereichFilter) &&
        (typFilter === 'ALL' || d.listen_typ === typFilter)
    );
  }, [dashList, bereichFilter, typFilter]);

  // Gruppiert nach Bereich
  const grouped = useMemo(() => {
    const map: Record<string, typeof dashList> = {};
    for (const d of filteredDashList) {
      const key = d.ber_name || '—';
      if (!map[key]) map[key] = [];
      map[key].push(d);
    }
    const sortedKeys = Object.keys(map).sort((a, b) => a.localeCompare(b));
    return { map, sortedKeys };
  }, [filteredDashList]);

  const configHref = useMemo(() => {
    const { type, dashID } = dashboard as any;
    if (!type || !dashID) return '#';
    return getConfigUrl(type, dashID);
  }, [dashboard]);

  const removeDashButtonView = !isCreate ? (
    <DialogContent>
      <Button
        variant="outlined"
        color="secondary"
        fullWidth
        onClick={(props as UpdateSettingDialogProps).remove}
      >
        <Trans>Remove Board</Trans>
      </Button>
    </DialogContent>
  ) : null;

  // Neue Liste erstellen und direkt auswählen
  const handleCreateList = async (args: {
    name: string;
    type: string;
    folderId: number | string;
    sources?: { idShort: string; type: string; text: string }[];
  }) => {
    if (!createList) throw new Error('createList helper nicht verfügbar');
    const result = await createList(args); // { newId }
    const newId = (result as any)?.newId;
    if (newId != null) {
      onChangeDash({ target: { value: `dash::${newId}` } });
    }
    return { newId };
  };

  const boardOptions = useMemo<BoardOption[]>(() => {
    const opts: BoardOption[] = [];

    grouped.sortedKeys.forEach((groupKey) => {
      const items = grouped.map[groupKey].slice().sort((a, b) => a.name.localeCompare(b.name));
      items.forEach((option: any) => {
        opts.push({
          label: option.name,
          value: `dash::${option.id}`,
          group: groupKey,
          subtitle: option.listen_typ,
        });
      });
    });

    if (iframeList.length > 0) {
      iframeList
        .slice()
        .sort((a, b) => a.name.localeCompare(b.name))
        .forEach((option: any) =>
          opts.push({
            label: option.name,
            value: `iframe::${option.id}`,
            group: 'Frame',
          })
        );
    }

    if (taskoNews.length > 0) {
      taskoNews
        .slice()
        .sort((a, b) => a.name.localeCompare(b.name))
        .forEach((option: any) =>
          opts.push({
            label: option.name,
            value: `news::${option.id}`,
            group: 'Tasko news',
          })
        );
    }

    return opts;
  }, [grouped, iframeList, taskoNews]);

  const boardOptionMap = useMemo(() => {
    const map = new Map<string, BoardOption>();
    boardOptions.forEach((opt) => map.set(opt.value, opt));
    return map;
  }, [boardOptions]);

  const areaOptions = useMemo<AreaOption[]>(() => {
    const opts: AreaOption[] = [];
    areaGroups.forEach((grp) => {
      grp.items.forEach((item) => {
        opts.push({
          label: item.label,
          value: `map::${extractNumericId(item.id)}`,
          group: grp.label,
        });
      });
    });
    return opts;
  }, [areaGroups]);

  const areaOptionMap = useMemo(() => {
    const map = new Map<string, AreaOption>();
    areaOptions.forEach((opt) => map.set(opt.value, opt));
    return map;
  }, [areaOptions]);

  const currentType = (dashboard as any).type;
  const currentDashId = (dashboard as any).dashID;
  const selectionKey =
    currentType && currentDashId !== '' && currentDashId != null
      ? `${currentType}::${currentDashId}`
      : '';

  const selectedBoardOption =
    currentType === 'map' ? null : boardOptionMap.get(selectionKey) ?? null;
  const selectedMapOption =
    currentType === 'map' ? areaOptionMap.get(selectionKey) ?? null : null;

  const handleBoardSelect = (_: any, option: BoardOption | null) => {
    if (!option) return;
    onChangeDash({ target: { value: option.value } });
  };

  const handleMapSelect = (_: any, option: AreaOption | null) => {
    if (!option) return;
    onChangeDash({ target: { value: option.value } });
  };

  const handleSourceModeChange = (_: React.ChangeEvent<HTMLInputElement>, value: string) => {
    if (value === 'map' && !canUseMap) {
      setSourceMode('existing');
      return;
    }
    setSourceMode(value as SourceMode);
  };

  const sourceOptions = useMemo(
    () =>
      [
        {
          value: 'existing' as const,
          title: <Trans>Bestehendes Board auswählen</Trans>,
          description: (
            <Trans>Suche nach vorhandenen Listen oder Frames und füge sie diesem Dashboard hinzu.</Trans>
          ),
        },
        ...(canUseMap
          ? [
              {
                value: 'map' as const,
                title: <Trans>Karte erzeugen mit allen Aufgaben innerhalb eines Bereichs</Trans>,
                description: (
                  <Trans>Lasse eine Kartenansicht erzeugen mit allen mit Position markierten Aufgaben innerhalb eines Bereichs.</Trans>
                ),
              },
            ]
          : []),
      ],
    [canUseMap],
  );

  const canSelectSource = sourceOptions.length > 1;

  const showConfigButton = configHref !== '#';

  return (
    <React.Fragment>
      {openDialogButton}
      <Dialog open={isOpen} onClose={closeDialog}>
        {canSelectSource && (
          <DialogContent>
            <FormControl fullWidth component="fieldset">
              <RadioGroup value={sourceMode} onChange={handleSourceModeChange}>
                {sourceOptions.map((opt) => (
                  <Box
                    key={opt.value}
                    sx={{
                      border: '1px solid rgba(0,0,0,0.12)',
                      borderRadius: 1,
                      mb: 1,
                      p: 1,
                    }}
                  >
                    <FormControlLabel
                      value={opt.value}
                      control={<Radio />}
                      label={
                        <Box>
                          <Typography variant="subtitle1">{opt.title}</Typography>
                          <Typography variant="body2" color="textSecondary">
                            {opt.description}
                          </Typography>
                        </Box>
                      }
                    />
                  </Box>
                ))}
              </RadioGroup>
            </FormControl>
          </DialogContent>
        )}

        {sourceMode === 'existing' && (
          <DialogContent>
            <Box display="flex" flexDirection="column" gap={2}>
              <Box>
                <Typography variant="subtitle1">
                  <Trans>Board aus einer Liste auswählen</Trans>
                </Typography>
              </Box>

              <Autocomplete<BoardOption>
                value={selectedBoardOption}
                options={boardOptions}
                disableClearable={Boolean(selectedBoardOption)}
                onChange={handleBoardSelect}
                groupBy={(option) => option.group}
                getOptionLabel={(option) => option.label}
                isOptionEqualToValue={(option, value) => option.value === value.value}
                autoHighlight
                noOptionsText={<Trans>Keine Einträge</Trans>}
                renderOption={(props, option) => (
                  <li {...props} key={option.value}>
                    <Box display="flex" flexDirection="column">
                      <Typography variant="body2">{option.label}</Typography>
                      {option.subtitle && (
                        <Typography variant="caption" color="textSecondary">
                          {option.subtitle}
                        </Typography>
                      )}
                    </Box>
                  </li>
                )}
                renderInput={(params) => (
                  <TextField
                    {...params}
                    label={<Trans>Liste auswählen</Trans>}
                    size="small"
                  />
                )}
              />
              {showConfigButton && (
                <Box display="flex" alignItems="center" justifyContent="flex-end">
                  <MuiLink
                    href={configHref}
                    target="_blank"
                    rel="noopener noreferrer"
                    style={{ color: 'inherit', display: 'flex', alignItems: 'center' }}
                    aria-label="Konfiguration öffnen"
                    title="Konfiguration öffnen"
                  >
                    <BuildIcon fontSize="small" style={{ opacity: 0.7, cursor: 'pointer' }} />
                  </MuiLink>
                </Box>
              )}
            </Box>
          </DialogContent>
        )}

        {sourceMode === 'map' && (
          <DialogContent>
            <Box display="flex" flexDirection="column" gap={2}>
              <Box>
                <Typography variant="subtitle1">
                  <Trans>Bereich auswählen</Trans>
                </Typography>
              </Box>
              <Autocomplete<AreaOption>
                value={selectedMapOption}
                options={areaOptions}
                disableClearable={Boolean(selectedMapOption)}
                loading={areasLoading}
                onChange={handleMapSelect}
                groupBy={(option) => option.group}
                getOptionLabel={(option) => option.label}
                isOptionEqualToValue={(option, value) => option.value === value.value}
                autoHighlight
                noOptionsText={
                  areasError
                    ? areasError
                    : <Trans>Keine Bereiche gefunden.</Trans>
                }
                loadingText={<Trans>Bereiche werden geladen…</Trans>}
                renderInput={(params) => (
                  <TextField
                    {...params}
                    label={<Trans>Bereich auswählen</Trans>}
                    size="small"
                  />
                )}
              />
            </Box>
          </DialogContent>
        )}

        {sourceMode === 'existing' && (
          <DialogContent>
            <Box display="flex" alignItems="center" gap={0.5}>
              <Typography variant="body2" color="textSecondary">
                <Trans>oder erstelle eine</Trans>
              </Typography>
              <Button
                variant="text"
                size="small"
                onClick={() => setCreateOwnOpen(true)}
                sx={{ textTransform: 'none', p: 0, minWidth: 'auto', color: '#1976d2' }}
              >
                <Trans>neue Liste</Trans>
              </Button>
            </Box>
          </DialogContent>
        )}

        {/* Erweiterte Optionen */}
        <DialogContent>
          <Button
            variant="text"
            onClick={() => setShowAdvanced((v) => !v)}
            sx={{ color: '#1976d2' }}
          >
            {showAdvanced ? <Trans>Erweiterte Optionen ausblenden</Trans> : <Trans>Erweiterte Optionen anzeigen</Trans>}
          </Button>
          <Collapse in={showAdvanced}>
            <Box mt={1}>
              <SelectForm
                value={(dashboard as any).refreshMinutes ?? 30}
                label={<Trans>Refresh Rate m</Trans>}
                onChange={onChange('refreshMinutes')}
              >
                <option value={1}>1</option>
                <option value={2}>2</option>
                <option value={5}>5</option>
                <option value={10}>10</option>
                <option value={15}>15</option>
                <option value={20}>20</option>
                <option value={30}>30</option>
              </SelectForm>

              <SelectForm
                label={<Trans>Count</Trans>}
                value={(dashboard as any).count ?? 100}
                onChange={onChange('count')}
              >
                <option value={1}>1</option>
                <option value={2}>2</option>
                <option value={5}>5</option>
                <option value={10}>10</option>
                <option value={20}>20</option>
                <option value={30}>30</option>
                <option value={40}>40</option>
                <option value={50}>50</option>
                <option value={100}>100</option>
              </SelectForm>
            </Box>
          </Collapse>
        </DialogContent>

        {/* Speichern */}
        <DialogContent>
          <Button
            variant="contained"
            color="primary"
            fullWidth
            onClick={createOrUpdate}
            disabled={(dashboard as any).dashID === ''}
          >
            <Trans>Save configuration</Trans>
          </Button>
        </DialogContent>



        {!isCreate && (
          <DialogContent>
            <Button
              variant="outlined"
              color="secondary"
              fullWidth
              onClick={(props as UpdateSettingDialogProps).remove}
            >
              <Trans>Remove Board</Trans>
            </Button>
          </DialogContent>
        )}
      </Dialog>

      {/* Erstellen-Dialog */}
      <CreateListDialog
        open={createOwnOpen}
        onClose={() => setCreateOwnOpen(false)}
        onCreate={handleCreateList}
        availableTypes={typen}
        availableAreaGroups={areaGroups}
      />
    </React.Fragment>
  );
};

export default SettingDialog;
