import { useState, useEffect, useMemo } from 'react';
import { Check, Package, Truck, ChevronDown } from 'lucide-react';
import { useShippingCountries } from '@/hooks/useWooCommerce';
import { useLang, useT, locale, type Lang } from '@/lib/i18n';

const COUNTRY_NAMES: Record<string, { nl: string; en: string }> = {
  NL: { nl: 'Nederland', en: 'Netherlands' }, BE: { nl: 'België', en: 'Belgium' }, DE: { nl: 'Duitsland', en: 'Germany' }, FR: { nl: 'Frankrijk', en: 'France' }, AT: { nl: 'Oostenrijk', en: 'Austria' },
  LU: { nl: 'Luxemburg', en: 'Luxembourg' }, GB: { nl: 'Verenigd Koninkrijk', en: 'United Kingdom' }, IT: { nl: 'Italië', en: 'Italy' }, ES: { nl: 'Spanje', en: 'Spain' }, PT: { nl: 'Portugal', en: 'Portugal' },
  PL: { nl: 'Polen', en: 'Poland' }, CZ: { nl: 'Tsjechië', en: 'Czechia' }, DK: { nl: 'Denemarken', en: 'Denmark' }, SE: { nl: 'Zweden', en: 'Sweden' }, FI: { nl: 'Finland', en: 'Finland' },
  IE: { nl: 'Ierland', en: 'Ireland' }, GR: { nl: 'Griekenland', en: 'Greece' }, HU: { nl: 'Hongarije', en: 'Hungary' }, RO: { nl: 'Roemenië', en: 'Romania' }, BG: { nl: 'Bulgarije', en: 'Bulgaria' },
  HR: { nl: 'Kroatië', en: 'Croatia' }, SK: { nl: 'Slowakije', en: 'Slovakia' }, SI: { nl: 'Slovenië', en: 'Slovenia' }, LT: { nl: 'Litouwen', en: 'Lithuania' }, LV: { nl: 'Letland', en: 'Latvia' },
  EE: { nl: 'Estland', en: 'Estonia' }, CY: { nl: 'Cyprus', en: 'Cyprus' }, MT: { nl: 'Malta', en: 'Malta' }, CH: { nl: 'Zwitserland', en: 'Switzerland' }, NO: { nl: 'Noorwegen', en: 'Norway' },
  US: { nl: 'Verenigde Staten', en: 'United States' }, CA: { nl: 'Canada', en: 'Canada' }, BA: { nl: 'Bosnië en Herzegovina', en: 'Bosnia and Herzegovina' }, MC: { nl: 'Monaco', en: 'Monaco' },
  AL: { nl: 'Albanië', en: 'Albania' }, AD: { nl: 'Andorra', en: 'Andorra' }, AM: { nl: 'Armenië', en: 'Armenia' }, AZ: { nl: 'Azerbeidzjan', en: 'Azerbaijan' }, BY: { nl: 'Wit-Rusland', en: 'Belarus' },
  GE: { nl: 'Georgië', en: 'Georgia' }, IS: { nl: 'IJsland', en: 'Iceland' }, XK: { nl: 'Kosovo', en: 'Kosovo' }, LI: { nl: 'Liechtenstein', en: 'Liechtenstein' }, MD: { nl: 'Moldavië', en: 'Moldova' },
  ME: { nl: 'Montenegro', en: 'Montenegro' }, MK: { nl: 'Noord-Macedonië', en: 'North Macedonia' }, RS: { nl: 'Servië', en: 'Serbia' }, SM: { nl: 'San Marino', en: 'San Marino' },
  TR: { nl: 'Turkije', en: 'Turkey' }, UA: { nl: 'Oekraïne', en: 'Ukraine' }, VA: { nl: 'Vaticaanstad', en: 'Vatican City' },
};

function countryName(code: string, lang: Lang): string {
  return COUNTRY_NAMES[code]?.[lang] || code;
}

const DELIVERY_DAYS: Record<string, [number, number]> = {
  NL: [1, 2], BE: [1, 3], LU: [2, 4], DE: [2, 4],
  FR: [3, 6], AT: [3, 6], GB: [4, 7], IT: [3, 6], ES: [4, 7], PT: [4, 7],
  DK: [3, 5], SE: [4, 7], FI: [5, 8], IE: [4, 7], PL: [3, 6], CZ: [3, 5],
  CH: [3, 6], NO: [4, 7],
};
const DEFAULT_DELIVERY: [number, number] = [5, 10];
const CUTOFF_HOUR = 12;
const INITIAL_TIME_LEFT = { hours: 0, minutes: 0, passed: false };

function getTimeUntilCutoff(): { hours: number; minutes: number; passed: boolean } {
  const now = new Date();
  const cet = new Date(now.toLocaleString('en-US', { timeZone: 'Europe/Amsterdam' }));
  const cutoff = new Date(cet);
  cutoff.setHours(CUTOFF_HOUR, 0, 0, 0);
  // Weekends/holidays: no same-day shipping, timer must not run.
  if (cet >= cutoff || isNonBusinessDay(cet)) return { hours: 0, minutes: 0, passed: true };
  const diff = cutoff.getTime() - cet.getTime();
  return { hours: Math.floor(diff / 3600000), minutes: Math.floor((diff % 3600000) / 60000), passed: false };
}

function getEasterSunday(year: number): Date {
  const a = year % 19;
  const b = Math.floor(year / 100);
  const c = year % 100;
  const d = Math.floor(b / 4);
  const e = b % 4;
  const f = Math.floor((b + 8) / 25);
  const g = Math.floor((b - f + 1) / 3);
  const h = (19 * a + b - d - g + 15) % 30;
  const i = Math.floor(c / 4);
  const k = c % 4;
  const l = (32 + 2 * e + 2 * i - h - k) % 7;
  const m = Math.floor((a + 11 * h + 22 * l) / 451);
  const month = Math.floor((h + l - 7 * m + 114) / 31);
  const day = ((h + l - 7 * m + 114) % 31) + 1;
  return new Date(year, month - 1, day);
}

function getDutchHolidays(year: number): Set<string> {
  const set = new Set<string>();
  const add = (d: Date) => set.add(d.toDateString());
  add(new Date(year, 0, 1));
  add(new Date(year, 3, 27));
  add(new Date(year, 11, 25));
  add(new Date(year, 11, 26));
  const easter = getEasterSunday(year);
  const goodFriday = new Date(easter); goodFriday.setDate(easter.getDate() - 2);
  const easterMonday = new Date(easter); easterMonday.setDate(easter.getDate() + 1);
  const ascension = new Date(easter); ascension.setDate(easter.getDate() + 39);
  const whitMonday = new Date(easter); whitMonday.setDate(easter.getDate() + 50);
  add(goodFriday);
  add(easterMonday);
  add(ascension);
  add(whitMonday);
  if (year % 5 === 0) add(new Date(year, 4, 5));
  return set;
}

const holidayCache = new Map<number, Set<string>>();
function isDutchHoliday(d: Date): boolean {
  const y = d.getFullYear();
  let set = holidayCache.get(y);
  if (!set) { set = getDutchHolidays(y); holidayCache.set(y, set); }
  return set.has(d.toDateString());
}

function isNonBusinessDay(d: Date): boolean {
  const day = d.getDay();
  return day === 0 || day === 6 || isDutchHoliday(d);
}

function addBusinessDays(date: Date, days: number): Date {
  const result = new Date(date);
  let added = 0;
  while (added < days) {
    result.setDate(result.getDate() + 1);
    if (!isNonBusinessDay(result)) added++;
  }
  return result;
}

function nextBusinessDay(date: Date): Date {
  const result = new Date(date);
  while (isNonBusinessDay(result)) {
    result.setDate(result.getDate() + 1);
  }
  return result;
}

function formatShortDate(d: Date, lang: Lang): string {
  return d.toLocaleDateString(locale(lang), { day: 'numeric', month: 'short' });
}
function formatDate(d: Date, lang: Lang): string {
  return d.toLocaleDateString(locale(lang), { day: 'numeric', month: 'long' });
}

function detectCountry(allowedCodes: string[]): string {
  try {
    const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
    const tzMap: Record<string, string> = {
      'Europe/Amsterdam': 'NL', 'Europe/Brussels': 'BE', 'Europe/Berlin': 'DE',
      'Europe/Paris': 'FR', 'Europe/Vienna': 'AT', 'Europe/Luxembourg': 'LU',
      'Europe/London': 'GB', 'Europe/Rome': 'IT', 'Europe/Madrid': 'ES',
      'Europe/Lisbon': 'PT', 'Europe/Warsaw': 'PL', 'Europe/Prague': 'CZ',
      'Europe/Copenhagen': 'DK', 'Europe/Stockholm': 'SE', 'Europe/Helsinki': 'FI',
      'Europe/Dublin': 'IE', 'Europe/Athens': 'GR', 'Europe/Budapest': 'HU',
      'Europe/Bucharest': 'RO', 'Europe/Sofia': 'BG', 'Europe/Zagreb': 'HR',
      'Europe/Bratislava': 'SK', 'Europe/Ljubljana': 'SI', 'Europe/Vilnius': 'LT',
      'Europe/Riga': 'LV', 'Europe/Tallinn': 'EE', 'Europe/Zurich': 'CH',
      'Europe/Oslo': 'NO', 'Asia/Nicosia': 'CY',
    };
    const detected = tzMap[tz];
    if (detected && allowedCodes.includes(detected)) return detected;
  } catch { /* ignore */ }
  try {
    const lang = navigator.language;
    const region = lang.split('-')[1]?.toUpperCase();
    if (region && allowedCodes.includes(region)) return region;
  } catch { /* ignore */ }
  return allowedCodes.includes('NL') ? 'NL' : allowedCodes[0] || 'NL';
}

export default function ShippingEstimate() {
  const lang = useLang();
  const t = useT();
  const { data: wcCountries } = useShippingCountries();
  const [hasMounted, setHasMounted] = useState(false);

  const countries = useMemo(() => {
    if (!wcCountries?.length) return [{ code: 'NL', name: countryName('NL', lang) }];
    return wcCountries
      .map((code) => ({ code, name: countryName(code, lang) }))
      .sort((a, b) => a.name.localeCompare(b.name, locale(lang)));
  }, [wcCountries, lang]);

  const [country, setCountry] = useState<string | null>(null);
  const [isCountryMenuOpen, setCountryMenuOpen] = useState(false);
  const [timeLeft, setTimeLeft] = useState(INITIAL_TIME_LEFT);

  useEffect(() => {
    setHasMounted(true);
    setTimeLeft(getTimeUntilCutoff());
  }, []);

  useEffect(() => {
    if (!hasMounted) return;
    if (countries.length && !country) {
      setCountry(detectCountry(countries.map((c) => c.code)));
    }
  }, [countries, country, hasMounted]);

  useEffect(() => {
    if (!hasMounted) return;
    const interval = setInterval(() => setTimeLeft(getTimeUntilCutoff()), 30_000);
    return () => clearInterval(interval);
  }, [hasMounted]);

  const selectedCode = country || 'NL';
  const deliveryDays = DELIVERY_DAYS[selectedCode] || DEFAULT_DELIVERY;

  const { deliveryRange, shippedLabel, shipDayText } = useMemo(() => {
    if (!hasMounted) return { shippedLabel: t('Vandaag', 'Today'), deliveryRange: t('1 - 2 werkdagen', '1 - 2 business days'), shipDayText: t('volgende werkdag', 'next business day') };
    const now = new Date();
    const cet = new Date(now.toLocaleString('en-US', { timeZone: 'Europe/Amsterdam' }));
    const today = new Date(cet);
    today.setHours(0, 0, 0, 0);
    let ship = new Date(today);
    if (timeLeft.passed || isNonBusinessDay(ship)) {
      ship = addBusinessDays(today, 1);
    }
    const tomorrow = new Date(today);
    tomorrow.setDate(tomorrow.getDate() + 1);
    const dayAfter = new Date(today);
    dayAfter.setDate(dayAfter.getDate() + 2);
    const weekdayName = ship.toLocaleDateString(locale(lang), { weekday: 'long' });
    let shippedLabel = `${weekdayName.charAt(0).toUpperCase() + weekdayName.slice(1)} ${formatShortDate(ship, lang)}`;
    if (ship.toDateString() === today.toDateString()) shippedLabel = t('Vandaag', 'Today');
    else if (ship.toDateString() === tomorrow.toDateString()) shippedLabel = t('Morgen', 'Tomorrow');
    else if (ship.toDateString() === dayAfter.toDateString()) shippedLabel = t(`Overmorgen (${weekdayName})`, `Day after tomorrow (${weekdayName})`);
    const deliverFrom = addBusinessDays(ship, deliveryDays[0]);
    const deliverTo = addBusinessDays(ship, deliveryDays[1]);
    const shipDayText =
      ship.toDateString() === tomorrow.toDateString() ? t('morgen', 'tomorrow') : t(`op ${weekdayName} ${formatShortDate(ship, lang)}`, `on ${weekdayName} ${formatShortDate(ship, lang)}`);
    return {
      shippedLabel,
      shipDayText,
      deliveryRange:
        deliverFrom.toDateString() === deliverTo.toDateString()
          ? formatDate(deliverFrom, lang)
          : `${formatShortDate(deliverFrom, lang)} - ${formatShortDate(deliverTo, lang)}`,
    };
  }, [timeLeft.passed, deliveryDays, hasMounted, lang, t]);

  return (
    <div className="rounded-2xl border border-border/50 bg-card p-5 space-y-4">
      {!timeLeft.passed ? (
        <div className="text-center space-y-0.5">
          <p className="text-sm font-bold text-primary">
            {t(`Bestel voor ${CUTOFF_HOUR}:00 voor verzending vandaag`, `Order before ${CUTOFF_HOUR}:00 for shipping today`)}
          </p>
          <p className="text-xs text-muted-foreground">
            {t('Bestel binnen', 'Order within')}{' '}
            <span className="font-bold text-foreground">{String(timeLeft.hours).padStart(2, '0')}</span> {t('uur', 'hours')}{' '}
            <span className="font-bold text-foreground">{String(timeLeft.minutes).padStart(2, '0')}</span> {t('minuten', 'minutes')}
          </p>
        </div>
      ) : (
        <p className="text-center text-sm font-semibold text-muted-foreground">
          {t(`Bestel nu, verzending ${shipDayText}`, `Order now, shipping ${shipDayText}`)}
        </p>
      )}

      <div className="flex items-start justify-between relative px-2">
        <div className="absolute top-5 left-[calc(8%+20px)] right-[calc(8%+20px)] h-0.5 bg-border" />
        <div className="flex flex-col items-center z-10 w-1/3">
          <div className="w-10 h-10 rounded-xl bg-primary text-primary-foreground flex items-center justify-center shadow-sm">
            <Check className="w-5 h-5" />
          </div>
          <span className="text-xs font-semibold mt-2">{t('Besteld', 'Ordered')}</span>
          <span className="text-[10px] text-muted-foreground italic">{t('Vandaag', 'Today')}</span>
        </div>
        <div className="flex flex-col items-center z-10 w-1/3">
          <div className="w-10 h-10 rounded-xl bg-muted text-muted-foreground flex items-center justify-center">
            <Package className="w-5 h-5" />
          </div>
          <span className="text-xs font-semibold mt-2">{t('Verzonden', 'Shipped')}</span>
          <span className="text-[10px] text-muted-foreground italic">{shippedLabel}</span>
        </div>
        <div className="flex flex-col items-center z-10 w-1/3">
          <div className="w-10 h-10 rounded-xl bg-muted text-muted-foreground flex items-center justify-center">
            <Truck className="w-5 h-5" />
          </div>
          <span className="text-xs font-semibold mt-2">{t('Bezorgd', 'Delivered')}</span>
          <span className="text-[10px] text-muted-foreground italic">{deliveryRange}</span>
        </div>
      </div>

      <div className="flex justify-center">
        <div className="relative inline-flex items-center">
          <button
            type="button"
            onClick={() => hasMounted && setCountryMenuOpen((open) => !open)}
            className="text-sm font-medium bg-surface border border-border rounded-xl pl-3 pr-8 py-2 cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary/30 focus:border-primary transition-colors"
            aria-haspopup="listbox"
            aria-expanded={hasMounted ? isCountryMenuOpen : false}
          >
            {selectedCode} {countryName(selectedCode, lang) || t('Nederland', 'Netherlands')}
          </button>
          {hasMounted && isCountryMenuOpen && (
            <div
              role="listbox"
              className="absolute bottom-full left-1/2 z-20 mb-2 max-h-56 w-56 -translate-x-1/2 overflow-auto rounded-xl border border-border bg-card p-1 shadow-elevated"
            >
              {countries.map((c) => (
                <button
                  key={c.code}
                  type="button"
                  role="option"
                  aria-selected={selectedCode === c.code}
                  onClick={() => {
                    setCountry(c.code);
                    setCountryMenuOpen(false);
                  }}
                  className="block w-full rounded-lg px-3 py-2 text-left text-sm hover:bg-muted aria-selected:bg-primary/10 aria-selected:text-primary"
                >
                  {c.code} {c.name}
                </button>
              ))}
            </div>
          )}
          <ChevronDown className="absolute right-2.5 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-muted-foreground pointer-events-none" />
        </div>
      </div>
    </div>
  );
}
