'use client';

import { useState, useMemo, useRef, useEffect } from 'react';
import { createPortal } from 'react-dom';
import { ChevronLeft, ChevronRight, Calendar as CalendarIcon, Globe, X, Star } from 'lucide-react';
import {
  gregorianToEthiopian,
  ethiopianToGregorian,
  formatEthiopianDate,
  getDaysInEthiopianMonth,
  ETHIOPIAN_MONTHS,
  type EthiopianDate,
} from '@/lib/ethiopian-calendar';
import { format } from 'date-fns';
import { formatFare } from '@/utils/fare-utils';
import { Schedule } from '@/types';

interface AlternativeDatesCalendarProps {
  // alternativeOutbound / alternativeInbound, as returned by /search — no fetching
  // of its own, this component is purely presentational over data the results
  // page already has in hand.
  alternatives: Schedule[];
  value?: Date;
  minDate?: Date;
  onChange: (date: Date) => void;
  label?: string;
}

interface DayInfo {
  hasAvailability: boolean;
  lowestFareMinor: number | null;
  displayCurrency: string | null;
}

const toDateKey = (date: Date) => {
  const y = date.getFullYear();
  const m = String(date.getMonth() + 1).padStart(2, '0');
  const d = String(date.getDate()).padStart(2, '0');
  return `${y}-${m}-${d}`;
};

export default function AlternativeDatesCalendar({
  value,
  minDate,
  onChange,
  label,
  alternatives,
}: AlternativeDatesCalendarProps) {
  const [isOpen, setIsOpen] = useState(false);
  const [isMobileView, setIsMobileView] = useState(false);
  const [calendarType, setCalendarType] = useState<'gregorian' | 'ethiopian'>('gregorian');
  const containerRef = useRef<HTMLDivElement>(null);

  // Day-level availability + cheapest fare, derived once from the alternatives
  // list — same "cheapest across faresByClass" logic used by the schedule cards
  // on the results page.
  const dayMap = useMemo(() => {
    const map = new Map<string, DayInfo>();
    for (const schedule of alternatives) {
      if (!schedule.departureAt) continue;
      const key = toDateKey(new Date(schedule.departureAt));
      const fares = (schedule.faresByClass ?? [])
        .map((f) => f.displayAmountMinor ?? f.baseFareMinor)
        .filter((n): n is number => !!n && n > 0);
      const lowestFareMinor = fares.length ? Math.min(...fares) : null;
      const displayCurrency = schedule.faresByClass?.[0]?.displayCurrency ?? null;
      const hasAvailability = !!schedule.hasAvailability;

      const existing = map.get(key);
      if (!existing) {
        map.set(key, { hasAvailability, lowestFareMinor: hasAvailability ? lowestFareMinor : null, displayCurrency: hasAvailability ? displayCurrency : null });
      } else {
        existing.hasAvailability = existing.hasAvailability || hasAvailability;
        if (hasAvailability && lowestFareMinor !== null && (existing.lowestFareMinor === null || lowestFareMinor < existing.lowestFareMinor)) {
          existing.lowestFareMinor = lowestFareMinor;
          existing.displayCurrency = displayCurrency;
        }
      }
    }
    return map;
  }, [alternatives]);

  const availableDateKeys = useMemo(
    () => Array.from(dayMap.entries()).filter(([, info]) => info.hasAvailability).map(([key]) => key),
    [dayMap],
  );

  const bestPriceDateKeys = useMemo(() => {
    const fares = availableDateKeys
      .map((key) => dayMap.get(key)!.lowestFareMinor)
      .filter((n): n is number => n !== null);
    if (fares.length === 0) return new Set<string>();
    const min = Math.min(...fares);
    return new Set(availableDateKeys.filter((key) => dayMap.get(key)!.lowestFareMinor === min));
  }, [availableDateKeys, dayMap]);

  // Pick the initial month to show: the requested date's month if it actually has
  // data, otherwise the month of whichever available date is closest to it — the
  // alternatives list has no day-window bound, so it can easily land in a
  // different month than the one originally searched.
  const initialFocusDate = useMemo(() => {
    const base = value ?? new Date();
    const baseMonthKey = `${base.getFullYear()}-${String(base.getMonth() + 1).padStart(2, '0')}`;
    if (availableDateKeys.some((key) => key.startsWith(baseMonthKey))) return base;

    let nearest: string | null = null;
    let nearestDiff = Infinity;
    for (const key of availableDateKeys) {
      const diff = Math.abs(new Date(`${key}T00:00:00`).getTime() - base.getTime());
      if (diff < nearestDiff) { nearestDiff = diff; nearest = key; }
    }
    return nearest ? new Date(`${nearest}T00:00:00`) : base;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const [viewMonth, setViewMonth] = useState(initialFocusDate.getMonth());
  const [viewYear, setViewYear] = useState(initialFocusDate.getFullYear());

  const initialEthDate = gregorianToEthiopian(initialFocusDate);
  const [ethViewMonth, setEthViewMonth] = useState(initialEthDate.month);
  const [ethViewYear, setEthViewYear] = useState(initialEthDate.year);

  useEffect(() => {
    const check = () => setIsMobileView(window.innerWidth < 768);
    check();
    window.addEventListener('resize', check);
    return () => window.removeEventListener('resize', check);
  }, []);

  useEffect(() => {
    if (isOpen) {
      document.body.style.overflow = 'hidden';
    } else {
      document.body.style.overflow = '';
    }
    return () => { document.body.style.overflow = ''; };
  }, [isOpen]);

  const toggleCalendarType = () => {
    const newType = calendarType === 'gregorian' ? 'ethiopian' : 'gregorian';
    const ref = value || new Date();
    if (newType === 'ethiopian') {
      const ethDate = gregorianToEthiopian(ref);
      setEthViewMonth(ethDate.month);
      setEthViewYear(ethDate.year);
    } else {
      setViewMonth(ref.getMonth());
      setViewYear(ref.getFullYear());
    }
    setCalendarType(newType);
  };

  const handleDateSelect = (date: Date) => {
    onChange(date);
    setIsOpen(false);
  };

  const handleEthiopianDateSelect = (ethDate: EthiopianDate) => {
    handleDateSelect(ethiopianToGregorian(ethDate));
  };

  const isBeforeMin = (date: Date) =>
    !!minDate && date < new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate());

  const renderGregorianCalendar = () => {
    const daysInMonth = new Date(viewYear, viewMonth + 1, 0).getDate();
    const firstDay = new Date(viewYear, viewMonth, 1).getDay();
    const days: (number | null)[] = Array(firstDay).fill(null);
    for (let d = 1; d <= daysInMonth; d++) days.push(d);
    const monthNames = ['January','February','March','April','May','June','July','August','September','October','November','December'];

    return (
      <div className="p-4">
        <div className="flex items-center justify-between mb-4">
          <button type="button" onClick={() => { if (viewMonth === 0) { setViewMonth(11); setViewYear(y => y - 1); } else setViewMonth(m => m - 1); }} className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors">
            <ChevronLeft className="w-5 h-5 text-gray-600 dark:text-gray-400" />
          </button>
          <span className="font-semibold text-base text-gray-900 dark:text-gray-100">{monthNames[viewMonth]} {viewYear}</span>
          <button type="button" onClick={() => { if (viewMonth === 11) { setViewMonth(0); setViewYear(y => y + 1); } else setViewMonth(m => m + 1); }} className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors">
            <ChevronRight className="w-5 h-5 text-gray-600 dark:text-gray-400" />
          </button>
        </div>
        <div className="grid grid-cols-7 gap-1 mb-2">
          {['Su','Mo','Tu','We','Th','Fr','Sa'].map(d => (
            <div key={d} className="text-center text-xs font-semibold text-gray-400 py-2">{d}</div>
          ))}
        </div>
        <div className="grid grid-cols-7 gap-1">
          {days.map((day, i) => {
            if (day === null) return <div key={`e-${i}`} />;
            const date = new Date(viewYear, viewMonth, day);
            const key = toDateKey(date);
            const dayInfo = dayMap.get(key);
            const isSelected = value && date.getDate() === value.getDate() && date.getMonth() === value.getMonth() && date.getFullYear() === value.getFullYear();
            const isToday = date.toDateString() === new Date().toDateString();
            const isDisabled = isBeforeMin(date) || !dayInfo?.hasAvailability;
            const isBestPrice = bestPriceDateKeys.has(key);
            return (
              <button key={day} type="button" onClick={() => !isDisabled && handleDateSelect(date)} disabled={isDisabled}
                className={`relative aspect-square flex flex-col items-center justify-center text-sm rounded-lg transition-all
                  ${isSelected ? 'bg-primary text-white font-semibold shadow-md scale-105' : ''}
                  ${isToday && !isSelected ? 'border-2 border-primary text-primary font-semibold' : ''}
                  ${!isSelected && !isToday && !isDisabled ? 'hover:bg-green-50 dark:hover:bg-green-900/20 text-gray-700 dark:text-gray-300' : ''}
                  ${isDisabled ? 'text-gray-300 dark:text-gray-600 cursor-not-allowed' : ''}`}>
                {isBestPrice && !isSelected && (
                  <Star className="w-2.5 h-2.5 absolute top-0.5 right-0.5 text-amber-500 fill-amber-500" />
                )}
                <span>{day}</span>
                {dayInfo?.hasAvailability && dayInfo.lowestFareMinor != null && (
                  <span className={`text-[8px] leading-none mt-0.5 ${isSelected ? 'text-white/90' : 'text-green-600 dark:text-green-400'}`}>
                    {formatFare(dayInfo.lowestFareMinor, dayInfo.displayCurrency ?? 'ETB').replace(/\.00$/, '')}
                  </span>
                )}
              </button>
            );
          })}
        </div>
      </div>
    );
  };

  const renderEthiopianCalendar = () => {
    const daysInMonth = getDaysInEthiopianMonth(ethViewYear, ethViewMonth);
    const firstDate = ethiopianToGregorian({ year: ethViewYear, month: ethViewMonth, day: 1 });
    const firstDayOfWeek = firstDate.getDay();
    const daysWithOffset: (number | null)[] = Array(firstDayOfWeek).fill(null);
    for (let d = 1; d <= daysInMonth; d++) daysWithOffset.push(d);
    const monthName = ETHIOPIAN_MONTHS[ethViewMonth - 1] || `Month ${ethViewMonth}`;

    return (
      <div className="p-4">
        <div className="flex items-center justify-between mb-4">
          <button type="button" onClick={() => { if (ethViewMonth === 1) { setEthViewMonth(13); setEthViewYear(y => y - 1); } else setEthViewMonth(m => m - 1); }} className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors">
            <ChevronLeft className="w-5 h-5 text-gray-600 dark:text-gray-400" />
          </button>
          <span className="font-semibold text-base text-gray-900 dark:text-gray-100">{monthName} {ethViewYear}</span>
          <button type="button" onClick={() => { if (ethViewMonth === 13) { setEthViewMonth(1); setEthViewYear(y => y + 1); } else setEthViewMonth(m => m + 1); }} className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors">
            <ChevronRight className="w-5 h-5 text-gray-600 dark:text-gray-400" />
          </button>
        </div>
        <div className="grid grid-cols-7 gap-1 mb-2">
          {['Su','Mo','Tu','We','Th','Fr','Sa'].map(d => (
            <div key={d} className="text-center text-xs font-semibold text-gray-400 py-2">{d}</div>
          ))}
        </div>
        <div className="grid grid-cols-7 gap-1">
          {daysWithOffset.map((day, i) => {
            if (day === null) return <div key={`e-${i}`} />;
            const ethDate: EthiopianDate = { year: ethViewYear, month: ethViewMonth, day };
            const gregDate = ethiopianToGregorian(ethDate);
            const key = toDateKey(gregDate);
            const dayInfo = dayMap.get(key);
            const isSelected = value && gregDate.getDate() === value.getDate() && gregDate.getMonth() === value.getMonth() && gregDate.getFullYear() === value.getFullYear();
            const todayEth = gregorianToEthiopian(new Date());
            const isToday = ethDate.day === todayEth.day && ethDate.month === todayEth.month && ethDate.year === todayEth.year;
            const isDisabled = isBeforeMin(gregDate) || !dayInfo?.hasAvailability;
            const isBestPrice = bestPriceDateKeys.has(key);
            return (
              <button key={day} type="button" onClick={() => !isDisabled && handleEthiopianDateSelect(ethDate)} disabled={isDisabled}
                className={`relative aspect-square flex flex-col items-center justify-center text-sm rounded-lg transition-all
                  ${isSelected ? 'bg-primary text-white font-semibold shadow-md scale-105' : ''}
                  ${isToday && !isSelected ? 'border-2 border-primary text-primary font-semibold' : ''}
                  ${!isSelected && !isToday && !isDisabled ? 'hover:bg-green-50 dark:hover:bg-green-900/20 text-gray-700 dark:text-gray-300' : ''}
                  ${isDisabled ? 'text-gray-300 dark:text-gray-600 cursor-not-allowed' : ''}`}>
                {isBestPrice && !isSelected && (
                  <Star className="w-2.5 h-2.5 absolute top-0.5 right-0.5 text-amber-500 fill-amber-500" />
                )}
                <span>{day}</span>
                {dayInfo?.hasAvailability && dayInfo.lowestFareMinor != null && (
                  <span className={`text-[8px] leading-none mt-0.5 ${isSelected ? 'text-white/90' : 'text-green-600 dark:text-green-400'}`}>
                    {formatFare(dayInfo.lowestFareMinor, dayInfo.displayCurrency ?? 'ETB').replace(/\.00$/, '')}
                  </span>
                )}
              </button>
            );
          })}
        </div>
      </div>
    );
  };

  const legend = (
    <div className="flex items-center gap-4 px-4 pb-3 text-xs text-gray-500 dark:text-gray-400">
      <span className="flex items-center gap-1.5">
        <span className="w-2.5 h-2.5 rounded-full bg-green-500" /> Available
      </span>
      <span className="flex items-center gap-1.5">
        <span className="w-2.5 h-2.5 rounded-full bg-gray-300 dark:bg-gray-600" /> Unavailable
      </span>
      <span className="flex items-center gap-1.5">
        <Star className="w-3 h-3 text-amber-500 fill-amber-500" /> Best price
      </span>
    </div>
  );

  const calendarFooter = value && (
    <div className="border-t border-gray-200 dark:border-gray-700 p-3 bg-gray-50 dark:bg-gray-800/60 space-y-1.5">
      <div className="flex items-center justify-between text-xs">
        <span className="text-gray-500 dark:text-gray-400">Gregorian:</span>
        <span className="font-medium text-gray-700 dark:text-gray-300">{format(value, 'MMMM d, yyyy')}</span>
      </div>
      <div className="flex items-center justify-between text-xs">
        <span className="text-gray-500 dark:text-gray-400">Ethiopian:</span>
        <span className="font-medium text-gray-700 dark:text-gray-300">{formatEthiopianDate(gregorianToEthiopian(value))}</span>
      </div>
    </div>
  );

  const modalContent = (
    <div className="flex flex-col h-full">
      <div className="flex items-center justify-between px-4 py-4 border-b border-gray-100 dark:border-gray-800 flex-shrink-0">
        <div className="flex items-center gap-2">
          <CalendarIcon className="w-4 h-4 text-primary" />
          <h2 className="text-base font-bold text-gray-900 dark:text-white">{label ? `Select ${label}` : 'Select a date'}</h2>
        </div>
        <button
          type="button"
          onClick={() => setIsOpen(false)}
          className="w-9 h-9 flex items-center justify-center rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
        >
          <X className="w-5 h-5 text-gray-500 dark:text-gray-400" />
        </button>
      </div>

      {legend}

      <div className="px-4 py-2.5 border-b border-gray-100 dark:border-gray-800 flex-shrink-0">
        <div className="flex rounded-lg overflow-hidden border-2 border-gray-200 dark:border-gray-700">
          <button
            type="button"
            onClick={() => calendarType !== 'gregorian' && toggleCalendarType()}
            className={`flex-1 flex items-center justify-center gap-1.5 py-2 text-xs font-semibold transition-colors ${
              calendarType === 'gregorian'
                ? 'bg-primary text-white'
                : 'bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700'
            }`}
          >
            <Globe className="w-3.5 h-3.5" />
            Gregorian
          </button>
          <button
            type="button"
            onClick={() => calendarType !== 'ethiopian' && toggleCalendarType()}
            className={`flex-1 flex items-center justify-center gap-1.5 py-2 text-xs font-semibold transition-colors ${
              calendarType === 'ethiopian'
                ? 'bg-primary text-white'
                : 'bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700'
            }`}
          >
            <Globe className="w-3.5 h-3.5" />
            Ethiopian
          </button>
        </div>
      </div>

      <div className="flex-1 overflow-y-auto">
        {calendarType === 'gregorian' ? renderGregorianCalendar() : renderEthiopianCalendar()}
        {calendarFooter}
      </div>

      {isMobileView && (
        <div className="flex-shrink-0 border-t border-gray-200 dark:border-gray-700 p-3 bg-white dark:bg-gray-900">
          <button
            type="button"
            onClick={() => setIsOpen(false)}
            className="w-full py-3 rounded-xl border-2 border-gray-200 dark:border-gray-700 text-sm font-semibold text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
          >
            Cancel
          </button>
        </div>
      )}
    </div>
  );

  return (
    <div className="relative" ref={containerRef}>
      <button
        type="button"
        onClick={() => setIsOpen(true)}
        className="w-full min-w-0 px-4 py-3.5 border-2 border-dashed border-primary/40 rounded-xl focus:outline-none focus:ring-2 focus:ring-primary/30 focus:border-primary text-center flex items-center justify-center gap-2 bg-primary/5 hover:bg-primary/10 dark:bg-primary/10 dark:hover:bg-primary/15 transition-all group"
      >
        <CalendarIcon className="w-4 h-4 text-primary flex-shrink-0" />
        <span className="text-sm font-semibold text-primary">
          {`Click here to see available ${label ? label.toLowerCase() + " " : ""}dates`}
        </span>
      </button>

      {isOpen && createPortal(
        <>
          {isMobileView ? (
            <div
              className="fixed inset-0 z-[100] bg-white dark:bg-gray-900 flex flex-col"
              style={{ animation: 'mdp-slide-up 0.25s cubic-bezier(0.32,0.72,0,1)' }}
            >
              {modalContent}
            </div>
          ) : (
            <>
              <div className="fixed inset-0 z-[99] bg-black/40 backdrop-blur-sm" onClick={() => setIsOpen(false)} />
              <div className="fixed inset-0 z-[100] flex items-center justify-center p-4 pointer-events-none">
                <div
                  className="bg-white dark:bg-gray-900 rounded-2xl shadow-2xl border border-gray-200 dark:border-gray-700 w-full max-w-sm pointer-events-auto"
                  style={{ animation: 'mdp-scale-in 0.2s cubic-bezier(0.34,1.56,0.64,1)' }}
                >
                  {modalContent}
                </div>
              </div>
            </>
          )}

          <style>{`
            @keyframes mdp-slide-up {
              from { transform: translateY(100%); opacity: 0; }
              to   { transform: translateY(0);    opacity: 1; }
            }
            @keyframes mdp-scale-in {
              from { transform: scale(0.92); opacity: 0; }
              to   { transform: scale(1);    opacity: 1; }
            }
          `}</style>
        </>,
        document.body
      )}
    </div>
  );
}
