import React, { useContext, useMemo, useState, useEffect } from 'react';
import axios from 'B/axios';
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 { 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';
import { Position } from '../types';

interface SettingDialogBase {
  openDialogButton: React.ReactElement | null;
  isOpen: boolean;
  dashboard: NewDash | Dash;
  closeDialog: () => void;
  onChange: (v: OnChangeProps) => (e: any) => void;
  onChangeDash: (e: any) => void;
  position?: Position | null;
}
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 === 'iframe') return `/iframes/${id}/edit`;
  if (type === 'news') return `/news/${id}/edit`;
  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 WidthMode = 'absolute' | 'percent';

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,
    position,
  } = 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 [showAdvanced, setShowAdvanced] = useState(false);
  const [createOwnOpen, setCreateOwnOpen] = useState(false);

  // Bereiche für Map-Card-Auswahl
  const [areaGroups, setAreaGroups] = useState<FolderGroup[]>([]);
  const [areasLoading, setAreasLoading] = useState(false);
  const [areasError, setAreasError] = useState<string>('');
  const [widthMode, setWidthMode] = useState<WidthMode>('absolute');
  const [widthInput, setWidthInput] = useState('');
  const [currentWidthPx, setCurrentWidthPx] = useState<number | null>(null);
  const [isWidthSaving, setIsWidthSaving] = useState(false);
  const [widthError, setWidthError] = useState('');
  const [widthSuccess, setWidthSuccess] = useState('');

  useEffect(() => {
    // Bereiche laden, sobald Dialog geöffnet ist
    if (!isOpen) 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]);

  // 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 width = Number(position?.width);
    if (Number.isFinite(width) && width > 0) {
      setCurrentWidthPx(width);
      setWidthInput(String(width));
    } else {
      setCurrentWidthPx(null);
      setWidthInput('');
    }
    setWidthMode('absolute');
    setWidthError('');
    setWidthSuccess('');
  }, [isOpen, position]);

  useEffect(() => {
    if (!widthSuccess) return;
    const timer = setTimeout(() => setWidthSuccess(''), 3000);
    return () => clearTimeout(timer);
  }, [widthSuccess]);

  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 typen = useMemo(() => unique(dashList, 'listen_typ'), [dashList]); // -> wird im CreateListDialog genutzt
  const grouped = useMemo(() => {
    const map: Record<string, typeof dashList> = {};
    for (const d of dashList) {
      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 };
  }, [dashList]);

  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 viewportWidth =
    typeof window !== 'undefined'
      ? window.innerWidth || (typeof document !== 'undefined' ? document.documentElement?.clientWidth || 0 : 0)
      : 0;
  const currentWidthPercent =
    currentWidthPx != null && viewportWidth > 0
      ? Math.round((currentWidthPx / viewportWidth) * 1000) / 10
      : null;
  const currentWidthPercentLabel =
    currentWidthPercent != null ? currentWidthPercent.toFixed(1) : null;
  const widthInputLabel = widthMode === 'percent' ? <Trans>Breite (%)</Trans> : <Trans>Breite (px)</Trans>;
  const widthValueNumber = Number(widthInput);
  const widthValueInvalid = !Number.isFinite(widthValueNumber) || widthValueNumber <= 0;
  const isWidthApplyDisabled = isWidthSaving || !widthInput || widthValueInvalid;
  const widthModeSelectId = 'dash-card-width-mode';
  const widthInputId = 'dash-card-width-input';

  const clampNumber = (value: number | null | undefined) => {
    const numeric = Number(value);
    if (!Number.isFinite(numeric)) return 0;
    return Math.max(0, Math.round(numeric));
  };

  const persistWidth = async (widthPx: number) => {
    if (!position) throw new Error('missing position');
    const dashId = (dashboard as Dash)?.id;
    if (!dashId) throw new Error('missing dash id');
    const payload = {
      x: clampNumber(position?.x),
      y: clampNumber(position?.y),
      width: clampNumber(widthPx),
      height: clampNumber(position?.height),
      z_index: clampNumber(position?.z_index ?? 100),
    };
    await axios.post('/dashboardpos/save', { dash_id: dashId, dash_pos: payload });
  };

  const handleApplyWidth = async () => {
    if (!position) {
      setWidthError('Keine Positionsdaten vorhanden.');
      setWidthSuccess('');
      return;
    }
    const numericValue = Number(widthInput);
    if (!Number.isFinite(numericValue) || numericValue <= 0) {
      setWidthError('Bitte eine gültige Breite angeben.');
      setWidthSuccess('');
      return;
    }

    let widthPx = 0;
    if (widthMode === 'percent') {
      if (viewportWidth <= 0) {
        setWidthError('Bildschirmbreite konnte nicht ermittelt werden.');
        setWidthSuccess('');
        return;
      }
      widthPx = Math.max(1, Math.round((viewportWidth * numericValue) / 100));
    } else {
      widthPx = Math.max(1, Math.round(numericValue));
    }

    setIsWidthSaving(true);
    setWidthError('');
    setWidthSuccess('');
    try {
      await persistWidth(widthPx);
      setCurrentWidthPx(widthPx);
      setWidthSuccess('Breite gespeichert.');
    } catch (err) {
      console.error('Breite speichern fehlgeschlagen', err);
      setWidthError('Breite konnte nicht gespeichert werden.');
    } finally {
      setIsWidthSaving(false);
    }
  };

  const showConfigButton = configHref !== '#';

  return (
    <React.Fragment>
      {openDialogButton}
      <Dialog open={isOpen} onClose={closeDialog}>
        <DialogContent>
          <Box display="flex" flexDirection="column" gap={1.5}>
            <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>

        {/* Erweiterte Optionen */}
        <DialogContent>
          <Button variant="text" onClick={() => setShowAdvanced((v) => !v)} sx={{ color: '#000000' }}>
            {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>
            
        {position && (
          <DialogContent>
            <Box display="flex" flexDirection="column" gap={1.5}>
              <Typography variant="subtitle1">
                <Trans>Kartenbreite festlegen</Trans>
              </Typography>
              <Typography variant="body2" color="textSecondary">
                {currentWidthPx != null ? (
                  currentWidthPercentLabel ? (
                    <Trans>
                      Aktuell: {currentWidthPx} px (~{currentWidthPercentLabel}% der Bildschirmbreite)
                    </Trans>
                  ) : (
                    <Trans>Aktuell: {currentWidthPx} px</Trans>
                  )
                ) : (
                  <Trans>Es ist noch keine Breite gespeichert.</Trans>
                )}
              </Typography>
              <Box display="flex" flexWrap="wrap" gap={1}>
                <FormControl sx={{ minWidth: 160 }}>
                  <InputLabel htmlFor={widthModeSelectId}>
                    <Trans>Modus</Trans>
                  </InputLabel>
                  <NativeSelect
                    value={widthMode}
                    id={widthModeSelectId}
                    onChange={(event) => setWidthMode(event.target.value as WidthMode)}
                  >
                    <option value="absolute">
                      <Trans>Pixel</Trans>
                    </option>
                    <option value="percent">
                      <Trans>Prozent</Trans>
                    </option>
                  </NativeSelect>
                </FormControl>
                <TextField
                  id={widthInputId}
                  type="number"
                  size="small"
                  label={widthInputLabel}
                  value={widthInput}
                  onChange={(event) => setWidthInput(event.target.value)}
                  inputProps={{ min: 1, step: 1 }}
                />
                <Button
                  variant="outlined"
                  onClick={handleApplyWidth}
                  disabled={isWidthApplyDisabled}
                  sx={{ color: '#000000', borderColor: '#000000' }}
                >
                  {isWidthSaving ? <Trans>Speichere…</Trans> : <Trans>Breite anwenden</Trans>}
                </Button>
              </Box>
              {widthError && (
                <Typography color="error" variant="body2">
                  {widthError}
                </Typography>
              )}
              {widthSuccess && (
                <Typography color="primary" variant="body2">
                  {widthSuccess}
                </Typography>
              )}
            </Box>
          </DialogContent>
        )}
          </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="warning"
              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;
