// Copyright (c) 2026 PowerOn AG
// All rights reserved.
/**
 * PeriodPicker - public component (Trigger + Popover).
 *
 * Carries a semantic value `{ preset, fromDate, toDate }`. Presets are
 * re-resolved on every render so dynamic ranges (`ytd`, `last12Months`, …)
 * stay fresh when the user revisits the page.
 *
 * Outside-click is detected via `mousedown` (not `click`): inner elements
 * are re-rendered on selection and would otherwise be detached from the DOM
 * when the click event reaches the document, breaking `closest()`.
 */

import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useLanguage } from '../../providers/language/LanguageContext';
import { FloatingPortal } from '../UiComponents/FloatingPortal';
import PeriodPickerPopover from './PeriodPickerPopover';
import {
  formatIsoDateDe,
  isPresetDisabled,
  isValueAllowed,
  resolvePeriod,
} from './PeriodPickerLogic';
import type {
  PeriodPickerProps,
  PeriodPreset,
  PeriodValue,
} from './PeriodPickerTypes';
import styles from './PeriodPicker.module.css';

// Re-export public types so callers can import everything from one place.
export type { PeriodPickerProps, PeriodPreset, PeriodValue, PeriodDirection, PeriodPresetKind, PeriodUnit } from './PeriodPickerTypes';
export { resolvePeriod, isPresetDisabled, isValueAllowed } from './PeriodPickerLogic';

const _DEFAULT_PRESET: PeriodPreset = { kind: 'ytd' };

function _formatTriggerLabel(value: PeriodValue | null, t: (k: string) => string, placeholder: string): string {
  if (!value) return placeholder;
  // "Alle" intentionally skips the range suffix: the sentinel dates
  // (1970-2999) would be noise in the trigger.
  if (value.preset.kind === 'allTime') return t('Alle');
  const range = `${formatIsoDateDe(value.fromDate)} – ${formatIsoDateDe(value.toDate)}`;
  switch (value.preset.kind) {
    case 'ytd':           return `${t('Laufendes Jahr')} · ${range}`;
    case 'lastYear':      return `${t('Letztes Jahr')} · ${range}`;
    case 'nextYear':      return `${t('Nächstes Jahr')} · ${range}`;
    case 'last12Months':  return `${t('Letzte 12 Monate')} · ${range}`;
    case 'next12Months':  return `${t('Nächste 12 Monate')} · ${range}`;
    case 'thisMonth':     return `${t('Dieser Monat')} · ${range}`;
    case 'lastMonth':     return `${t('Letzter Monat')} · ${range}`;
    case 'thisQuarter':   return `${t('Dieses Quartal')} · ${range}`;
    case 'lastQuarter':   return `${t('Letztes Quartal')} · ${range}`;
    case 'lastN': {
      const unitLabel = _unitLabelShort(value.preset.unit, t);
      return `${t('Letzte')} ${value.preset.amount} ${unitLabel} · ${range}`;
    }
    case 'nextN': {
      const unitLabel = _unitLabelShort(value.preset.unit, t);
      return `${t('Nächste')} ${value.preset.amount} ${unitLabel} · ${range}`;
    }
    case 'custom':
    default:
      return range;
  }
}

function _unitLabelShort(unit: 'day' | 'week' | 'month' | 'year', t: (k: string) => string): string {
  switch (unit) {
    case 'day':   return t('Tage');
    case 'week':  return t('Wochen');
    case 'month': return t('Monate');
    case 'year':  return t('Jahre');
  }
}

export const PeriodPicker: React.FC<PeriodPickerProps> = (props) => {
  const {
    value,
    onChange,
    direction = 'any',
    minDate,
    maxDate,
    enabledPresets,
    defaultPreset = _DEFAULT_PRESET,
    placeholder,
    disabled = false,
    className,
  } = props;
  const { t } = useLanguage();

  const constraints = useMemo(
    () => ({ direction, minDate, maxDate, enabledPresets }),
    [direction, minDate, maxDate, enabledPresets],
  );

  // Re-resolve semantic presets on every render so values stay fresh.
  const resolvedValue: PeriodValue | null = useMemo(() => {
    if (!value) return null;
    if (value.preset.kind === 'custom') return value;
    const r = resolvePeriod(value.preset, value);
    if (r.fromDate === value.fromDate && r.toDate === value.toDate) return value;
    return { preset: value.preset, fromDate: r.fromDate, toDate: r.toDate };
  }, [value]);

  const _resolvedTrigger = useMemo(
    () => _formatTriggerLabel(resolvedValue, t, placeholder || t('Zeitraum wählen')),
    [resolvedValue, t, placeholder],
  );

  const [open, setOpen] = useState(false);
  const triggerRef = useRef<HTMLButtonElement>(null);

  const _initialDraft: PeriodValue = useMemo(() => {
    if (resolvedValue) return resolvedValue;
    const preset = isPresetDisabled(defaultPreset.kind, constraints)
      ? ({ kind: 'custom' } as PeriodPreset)
      : defaultPreset;
    const r = resolvePeriod(preset);
    return { preset, fromDate: r.fromDate, toDate: r.toDate };
  }, [resolvedValue, defaultPreset, constraints]);

  const _handleApply = useCallback((next: PeriodValue) => {
    onChange(next);
    setOpen(false);
  }, [onChange]);

  const _handleCancel = useCallback(() => setOpen(false), []);

  // If parent-passed value violates constraints, fall back silently to the
  // default preset so the trigger never shows a forbidden range.
  useEffect(() => {
    if (resolvedValue && !isValueAllowed(resolvedValue, constraints)) {
      const fallbackPreset = isPresetDisabled(defaultPreset.kind, constraints)
        ? ({ kind: 'custom' } as PeriodPreset)
        : defaultPreset;
      const r = resolvePeriod(fallbackPreset, resolvedValue);
      onChange({ preset: fallbackPreset, fromDate: r.fromDate, toDate: r.toDate });
    }
  }, [resolvedValue, constraints, defaultPreset, onChange]);

  const triggerCls = [styles.trigger];
  if (open) triggerCls.push(styles.open);

  return (
    <div className={`${styles.wrapper}${className ? ` ${className}` : ''}`}>
      <button
        ref={triggerRef}
        type="button"
        className={triggerCls.join(' ')}
        onClick={() => setOpen((o) => !o)}
        disabled={disabled}
        aria-haspopup="dialog"
        aria-expanded={open}
      >
        <span className={styles.triggerIcon} aria-hidden>📅</span>
        <span className={styles.triggerText}>{_resolvedTrigger}</span>
        <span className={styles.triggerChev} aria-hidden>▾</span>
      </button>

      <FloatingPortal
        open={open}
        anchorRef={triggerRef}
        onClose={() => setOpen(false)}
        placement="auto"
      >
        <PeriodPickerPopover
          initialValue={_initialDraft}
          constraints={constraints}
          onApply={_handleApply}
          onCancel={_handleCancel}
        />
      </FloatingPortal>
    </div>
  );
};

export default PeriodPicker;
