// Copyright (c) 2026 PowerOn AG
// All rights reserved.
/**
 * Accordion schedule planner → updates ScheduleSpec; parent derives cron via buildCronFromSpec.
 */

import React, { useCallback, useMemo, useState } from 'react';
import {
  MINUTE_SELECT_OPTIONS,
  WEEKDAYS_MO_SO,
  type ScheduleSpec,
} from '../../utils/scheduleCron';
import { useLanguage } from '../../providers/language/LanguageContext';
import { AccordionList } from '../UiComponents';
import styles from './SchedulePlanner.module.css';

export type PlannerModeId = 'minutes' | 'hours' | 'days' | 'weeks' | 'months' | 'custom';

const PLANNER_MODE_IDS: PlannerModeId[] = [
  'minutes',
  'hours',
  'days',
  'weeks',
  'months',
  'custom',
];

function plannerModeFromSpec(spec: ScheduleSpec): PlannerModeId {
  const m = spec.mode;
  if (m === 'interval') {
    if (spec.intervalUnit === 'hours') return 'hours';
    if (spec.intervalUnit === 'days') return 'days';
    if (spec.intervalUnit === 'minutes') return 'minutes';
    return 'custom';
  }
  if (m === 'minutes') return 'minutes';
  if (m === 'hours') return 'hours';
  if (m === 'days' || m === 'daily') return 'days';
  if (m === 'weeks' || m === 'weekly' || m === 'weekdays') return 'weeks';
  if (m === 'months' || (m === 'calendar' && spec.calendarPeriod === 'monthly')) return 'months';
  return 'custom';
}

function withPlannerMode(spec: ScheduleSpec, id: PlannerModeId): ScheduleSpec {
  const base = { ...spec };
  switch (id) {
    case 'minutes':
      return {
        ...base,
        mode: 'minutes',
        intervalValue: Math.max(1, base.intervalValue || 15),
      };
    case 'hours':
      return {
        ...base,
        mode: 'hours',
        intervalValue: Math.max(1, base.intervalValue || 1),
      };
    case 'days':
      return {
        ...base,
        mode: 'days',
        intervalValue: Math.max(1, base.intervalValue || 1),
      };
    case 'weeks':
      return {
        ...base,
        mode: 'weeks',
        weeksInterval: Math.max(1, base.weeksInterval || 1),
        weekdays:
          base.weekdays.length > 0 ? [...base.weekdays] : [1, 2, 3, 4, 5],
      };
    case 'months':
      return {
        ...base,
        mode: 'months',
        intervalValue: Math.max(1, base.intervalValue || 1),
        monthDay: Math.min(28, Math.max(1, base.monthDay || 1)),
      };
    case 'custom':
      return {
        ...base,
        mode: 'custom',
        customCron: (base.customCron || '0 9 * * *').trim(),
      };
    default:
      return base;
  }
}

export interface SchedulePlannerProps {
  value: ScheduleSpec;
  onChange: (next: ScheduleSpec) => void;
  className?: string;
  disabled?: boolean;
}

export const SchedulePlanner: React.FC<SchedulePlannerProps> = ({
  value,
  onChange,
  className = '',
  disabled = false,
}) => {
  const { t } = useLanguage();
  const activeMode = useMemo(() => plannerModeFromSpec(value), [value]);
  const [openId, setOpenId] = useState<PlannerModeId | null>(null);

  const modeMeta = useMemo(
    () =>
      ({
        minutes: { label: t('Alle X Minuten') },
        hours: { label: t('Alle X Stunden') },
        days: { label: t('Täglich / alle X Tage') },
        weeks: { label: t('Wöchentlich') },
        months: { label: t('Monatlich') },
        custom: { label: t('Custom (Cron)') },
      }) as const,
    [t]
  );

  const push = useCallback(
    (next: ScheduleSpec) => {
      if (!disabled) onChange(next);
    },
    [disabled, onChange]
  );

  const handleOpenChange = (next: PlannerModeId | null) => {
    setOpenId(next);
    if (next != null) {
      push(withPlannerMode(value, next));
    }
  };

  const hourOptions = useMemo(
    () => Array.from({ length: 24 }, (_, i) => i),
    []
  );

  const renderBody = (id: PlannerModeId) => {
    const v = plannerModeFromSpec(value) === id ? value : withPlannerMode(value, id);
    switch (id) {
      case 'minutes':
        return (
          <div className={styles.fields}>
            <div className={styles.field}>
              <span className={styles.fieldLabel}>{t('Alle')}</span>
              <input
                type="number"
                min={1}
                max={59}
                className={styles.numberInput}
                value={v.intervalValue}
                onChange={(e) =>
                  push({
                    ...v,
                    mode: 'minutes',
                    intervalValue: Math.min(59, Math.max(1, Number(e.target.value) || 1)),
                  })
                }
              />
              <span className={styles.unit}>{t('Minuten')}</span>
            </div>
          </div>
        );
      case 'hours':
        return (
          <div className={styles.fields}>
            <div className={styles.field}>
              <span className={styles.fieldLabel}>{t('Alle')}</span>
              <input
                type="number"
                min={1}
                max={23}
                className={styles.numberInput}
                value={v.intervalValue}
                onChange={(e) =>
                  push({
                    ...v,
                    mode: 'hours',
                    intervalValue: Math.min(23, Math.max(1, Number(e.target.value) || 1)),
                  })
                }
              />
              <span className={styles.unit}>{t('Stunden')}</span>
            </div>
            <div className={styles.field}>
              <span className={styles.fieldLabel}>{t('Bei Minute')}</span>
              <select
                className={styles.select}
                value={v.minute}
                onChange={(e) =>
                  push({
                    ...v,
                    mode: 'hours',
                    minute: Number(e.target.value),
                  })
                }
              >
                {MINUTE_SELECT_OPTIONS.map((m) => (
                  <option key={m} value={m}>
                    {String(m).padStart(2, '0')}
                  </option>
                ))}
              </select>
            </div>
          </div>
        );
      case 'days':
        return (
          <div className={styles.fields}>
            <div className={styles.field}>
              <span className={styles.fieldLabel}>{t('Alle')}</span>
              <input
                type="number"
                min={1}
                max={31}
                className={styles.numberInput}
                value={v.intervalValue}
                onChange={(e) =>
                  push({
                    ...v,
                    mode: 'days',
                    intervalValue: Math.min(31, Math.max(1, Number(e.target.value) || 1)),
                  })
                }
              />
              <span className={styles.unit}>{t('Tage')}</span>
            </div>
            <div className={styles.field}>
              <span className={styles.fieldLabel}>{t('Uhrzeit')}</span>
              <div className={styles.timeRow}>
                <select
                  className={styles.select}
                  value={v.hour}
                  onChange={(e) =>
                    push({
                      ...v,
                      mode: 'days',
                      hour: Number(e.target.value),
                    })
                  }
                >
                  {hourOptions.map((h) => (
                    <option key={h} value={h}>
                      {String(h).padStart(2, '0')}
                    </option>
                  ))}
                </select>
                <span className={styles.timeSep}>:</span>
                <select
                  className={styles.select}
                  value={v.minute}
                  onChange={(e) =>
                    push({
                      ...v,
                      mode: 'days',
                      minute: Number(e.target.value),
                    })
                  }
                >
                  {MINUTE_SELECT_OPTIONS.map((m) => (
                    <option key={m} value={m}>
                      {String(m).padStart(2, '0')}
                    </option>
                  ))}
                </select>
              </div>
            </div>
            <p className={styles.cronHint}>
              {t(
                'Hinweis: „Alle N Tage“ entspricht in Cron einem Schritt im Tag-des-Monats-Feld, nicht zwingend jedem Kalendertag.'
              )}
            </p>
          </div>
        );
      case 'weeks':
        return (
          <div className={styles.fields}>
            <div className={styles.field}>
              <span className={styles.fieldLabel}>{t('Alle')}</span>
              <input
                type="number"
                min={1}
                max={52}
                className={styles.numberInput}
                value={v.weeksInterval ?? 1}
                onChange={(e) =>
                  push({
                    ...v,
                    mode: 'weeks',
                    weeksInterval: Math.min(52, Math.max(1, Number(e.target.value) || 1)),
                  })
                }
              />
              <span className={styles.unit}>{t('Wochen')}</span>
            </div>
            {(v.weeksInterval ?? 1) > 1 && (
              <p className={styles.warn}>
                {t(
                  'Mehr als jede Woche: der erzeugte Cron entspricht vorläufig wöchentlich (ein Wochen-Intervall > 1 ist im Standard-Cron nicht exakt abbildbar).'
                )}
              </p>
            )}
            <div className={`${styles.field} ${styles.fieldStart}`}>
              <span className={`${styles.fieldLabel} ${styles.fieldLabelTop}`}>
                {t('Wochentage')}
              </span>
              <div className={styles.daysRow}>
                {WEEKDAYS_MO_SO.map(({ cronDow }) => (
                  <button
                    key={cronDow}
                    type="button"
                    data-schedule-day=""
                    className={`${styles.dayBtn} ${v.weekdays.includes(cronDow) ? styles.dayBtnSel : ''}`}
                    onClick={() => {
                      const next = { ...v, mode: 'weeks' as const };
                      const set = new Set(next.weekdays);
                      if (set.has(cronDow)) set.delete(cronDow);
                      else set.add(cronDow);
                      let wd = [...set];
                      if (wd.length === 0) wd = [cronDow];
                      wd.sort((a, b) => {
                        const o = (x: number) => (x === 0 ? 7 : x);
                        return o(a) - o(b);
                      });
                      push({ ...next, weekdays: wd });
                    }}
                  >
                    {cronDow === 1
                      ? t('Mo')
                      : cronDow === 2
                        ? t('Di')
                        : cronDow === 3
                          ? t('Mi')
                          : cronDow === 4
                            ? t('Do')
                            : cronDow === 5
                              ? t('Fr')
                              : cronDow === 6
                                ? t('Sa')
                                : t('So')}
                  </button>
                ))}
              </div>
            </div>
            <div className={styles.field}>
              <span className={styles.fieldLabel}>{t('Uhrzeit')}</span>
              <div className={styles.timeRow}>
                <select
                  className={styles.select}
                  value={v.hour}
                  onChange={(e) =>
                    push({
                      ...v,
                      mode: 'weeks',
                      hour: Number(e.target.value),
                    })
                  }
                >
                  {hourOptions.map((h) => (
                    <option key={h} value={h}>
                      {String(h).padStart(2, '0')}
                    </option>
                  ))}
                </select>
                <span className={styles.timeSep}>:</span>
                <select
                  className={styles.select}
                  value={v.minute}
                  onChange={(e) =>
                    push({
                      ...v,
                      mode: 'weeks',
                      minute: Number(e.target.value),
                    })
                  }
                >
                  {MINUTE_SELECT_OPTIONS.map((m) => (
                    <option key={m} value={m}>
                      {String(m).padStart(2, '0')}
                    </option>
                  ))}
                </select>
              </div>
            </div>
          </div>
        );
      case 'months':
        return (
          <div className={styles.fields}>
            <div className={styles.field}>
              <span className={styles.fieldLabel}>{t('Alle')}</span>
              <input
                type="number"
                min={1}
                max={12}
                className={styles.numberInput}
                value={v.intervalValue}
                onChange={(e) =>
                  push({
                    ...v,
                    mode: 'months',
                    intervalValue: Math.min(12, Math.max(1, Number(e.target.value) || 1)),
                  })
                }
              />
              <span className={styles.unit}>{t('Monate')}</span>
            </div>
            <div className={styles.field}>
              <span className={styles.fieldLabel}>{t('Tag des Monats')}</span>
              <input
                type="number"
                min={1}
                max={28}
                className={styles.numberInput}
                value={Math.min(28, v.monthDay)}
                onChange={(e) =>
                  push({
                    ...v,
                    mode: 'months',
                    monthDay: Math.min(28, Math.max(1, Number(e.target.value) || 1)),
                  })
                }
              />
            </div>
            <div className={styles.field}>
              <span className={styles.fieldLabel}>{t('Uhrzeit')}</span>
              <div className={styles.timeRow}>
                <select
                  className={styles.select}
                  value={v.hour}
                  onChange={(e) =>
                    push({
                      ...v,
                      mode: 'months',
                      hour: Number(e.target.value),
                    })
                  }
                >
                  {hourOptions.map((h) => (
                    <option key={h} value={h}>
                      {String(h).padStart(2, '0')}
                    </option>
                  ))}
                </select>
                <span className={styles.timeSep}>:</span>
                <select
                  className={styles.select}
                  value={v.minute}
                  onChange={(e) =>
                    push({
                      ...v,
                      mode: 'months',
                      minute: Number(e.target.value),
                    })
                  }
                >
                  {MINUTE_SELECT_OPTIONS.map((m) => (
                    <option key={m} value={m}>
                      {String(m).padStart(2, '0')}
                    </option>
                  ))}
                </select>
              </div>
            </div>
          </div>
        );
      case 'custom':
        return (
          <div className={styles.fields}>
            <div className={`${styles.field} ${styles.fieldStart}`}>
              <span className={`${styles.fieldLabel} ${styles.fieldLabelTop}`}>
                {t('Ausdruck')}
              </span>
              <div>
                <input
                  type="text"
                  className={styles.cronInput}
                  value={v.customCron}
                  onChange={(e) =>
                    push({
                      ...v,
                      mode: 'custom',
                      customCron: e.target.value,
                    })
                  }
                  spellCheck={false}
                />
                <div className={styles.cronHint}>
                  {t('Cron')}: {t('Minute')} · {t('Stunde')} · {t('Tag')} · {t('Monat')} ·{' '}
                  {t('Wochentag')}
                  {' · '}[{t('Sekunde')} {t('optional')}]
                  <br />
                  {t('z.B.')}{' '}
                  <code>0 9 * * 3,5</code>
                </div>
              </div>
            </div>
          </div>
        );
      default:
        return null;
    }
  };

  return (
    <div className={`${styles.wrap} ${className} ${disabled ? styles.disabled : ''}`}>
      <p className={styles.intro}>
        {t(
          'Legen Sie fest, wann dieser Workflow automatisch laufen soll. Der Cron-Ausdruck wird für die API erzeugt.'
        )}
      </p>
      <AccordionList<PlannerModeId>
        items={PLANNER_MODE_IDS.map((mid) => ({
          id: mid,
          title: modeMeta[mid].label,
          children: renderBody(mid),
        }))}
        showSelectionIndicator
        selectedId={activeMode}
        openId={openId}
        onOpenChange={handleOpenChange}
        disabled={disabled}
      />
    </div>
  );
};
