'use client';

/**
 * Travel Stepper — Поиск → Места → Маршрут → Отели → Билеты
 * docs/architecture: 01-perplexity-analogue-design.md §2.2.D
 * Состояние сохраняется в travel-svc (Redis) или sessionStorage (fallback)
 */

import { useCallback, useEffect, useMemo, useState } from 'react';
import { cn } from '@/lib/utils';
import {
  Search,
  MapPin,
  Route,
  Hotel,
  Plane,
  ChevronRight,
  ChevronLeft,
  X,
} from 'lucide-react';

const STEPS = [
  { id: 'search', label: 'Search', icon: Search },
  { id: 'places', label: 'Places', icon: MapPin },
  { id: 'route', label: 'Route', icon: Route },
  { id: 'hotels', label: 'Hotels', icon: Hotel },
  { id: 'tickets', label: 'Tickets', icon: Plane },
] as const;

export type TravelStepperStepId = (typeof STEPS)[number]['id'];

export interface ItineraryDay {
  day: number;
  title: string;
  activities: string[];
  tips?: string;
}

export interface TravelStepperState {
  step: TravelStepperStepId;
  searchQuery: string;
  places: string[];
  route: string | null;
  itineraryDays: number;
  hotels: string[];
  tickets: string | null;
  updatedAt: number;
}

const DEFAULT_STATE: TravelStepperState = {
  step: 'search',
  searchQuery: '',
  places: [],
  route: null,
  itineraryDays: 3,
  hotels: [],
  tickets: null,
  updatedAt: Date.now(),
};

const STORAGE_KEY = 'gooseek_travel_stepper_session';
const API_PREFIX = '/api/v1/travel';

function getOrCreateSessionId(): string {
  if (typeof window === 'undefined') return '';
  let id = sessionStorage.getItem(STORAGE_KEY);
  if (!id) {
    id = crypto.randomUUID();
    sessionStorage.setItem(STORAGE_KEY, id);
  }
  return id;
}

async function saveState(sessionId: string, state: TravelStepperState): Promise<boolean> {
  try {
    const res = await fetch(`${API_PREFIX}/stepper/state`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ sessionId, state }),
    });
    return res.ok;
  } catch {
    return false;
  }
}

async function fetchItinerary(query: string, days: number): Promise<{ days: ItineraryDay[]; summary?: string } | null> {
  try {
    const res = await fetch(`${API_PREFIX}/itinerary`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ query, days }),
      signal: AbortSignal.timeout(90000),
    });
    const data = await res.json();
    if (data?.days?.length) return data;
    return null;
  } catch {
    return null;
  }
}

async function loadState(sessionId: string): Promise<TravelStepperState | null> {
  try {
    const res = await fetch(`${API_PREFIX}/stepper/state/${sessionId}`);
    const data = await res.json();
    return data?.state ?? null;
  } catch {
    return null;
  }
}

interface TravelStepperProps {
  onClose: () => void;
}

export default function TravelStepper({ onClose }: TravelStepperProps) {
  const [sessionId, setSessionId] = useState('');
  const [state, setState] = useState<TravelStepperState>(DEFAULT_STATE);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [itineraryData, setItineraryData] = useState<{ days: ItineraryDay[]; summary?: string } | null>(null);
  const [itineraryLoading, setItineraryLoading] = useState(false);
  const [itineraryError, setItineraryError] = useState<string | null>(null);

  const stepIndex = useMemo(
    () => STEPS.findIndex((s) => s.id === state.step),
    [state.step]
  );
  const canPrev = stepIndex > 0;
  const canNext = stepIndex < STEPS.length - 1;

  const persistState = useCallback(
    async (next: TravelStepperState) => {
      if (!sessionId) return;
      setSaving(true);
      const ok = await saveState(sessionId, next);
      setSaving(false);
      if (!ok && typeof window !== 'undefined') {
        try {
          sessionStorage.setItem('gooseek_travel_stepper_state', JSON.stringify(next));
        } catch {
          /* noop */
        }
      }
    },
    [sessionId]
  );

  useEffect(() => {
    const id = getOrCreateSessionId();
    setSessionId(id);
    let cancelled = false;
    (async () => {
      const loaded = await loadState(id);
      if (cancelled) return;
      if (loaded && typeof loaded.step === 'string') {
        setState({
          ...DEFAULT_STATE,
          ...loaded,
          updatedAt: Date.now(),
        });
      } else if (typeof window !== 'undefined') {
        try {
          const raw = sessionStorage.getItem('gooseek_travel_stepper_state');
          if (raw) {
            const parsed = JSON.parse(raw) as Partial<TravelStepperState>;
            if (parsed?.step) {
              setState({ ...DEFAULT_STATE, ...parsed });
            }
          }
        } catch {
          /* noop */
        }
      }
      setLoading(false);
    })();
    return () => {
      cancelled = true;
    };
  }, []);

  const goTo = useCallback(
    (step: TravelStepperStepId) => {
      const next = { ...state, step, updatedAt: Date.now() };
      setState(next);
      persistState(next);
    },
    [state, persistState]
  );

  const goPrev = useCallback(() => {
    if (!canPrev) return;
    const prevStep = STEPS[stepIndex - 1].id;
    goTo(prevStep);
  }, [canPrev, stepIndex, goTo]);

  const goNext = useCallback(() => {
    if (!canNext) return;
    const nextStep = STEPS[stepIndex + 1].id;
    goTo(nextStep);
  }, [canNext, stepIndex, goTo]);

  useEffect(() => {
    if (state.step !== 'route' || !state.searchQuery.trim()) {
      setItineraryData(null);
      setItineraryError(null);
      return;
    }
    let cancelled = false;
    setItineraryLoading(true);
    setItineraryError(null);
    fetchItinerary(state.searchQuery, state.itineraryDays ?? 3)
      .then((data) => {
        if (!cancelled && data) setItineraryData(data);
        else if (!cancelled) setItineraryError('Could not generate itinerary. OPENAI_API_KEY may be missing.');
      })
      .catch(() => {
        if (!cancelled) setItineraryError('Request failed. Try again.');
      })
      .finally(() => {
        if (!cancelled) setItineraryLoading(false);
      });
    return () => { cancelled = true; };
  }, [state.step, state.searchQuery, state.itineraryDays]);

  const updateSearch = useCallback(
    (q: string) => {
      const next = { ...state, searchQuery: q, updatedAt: Date.now() };
      setState(next);
      persistState(next);
    },
    [state, persistState]
  );

  const updateItineraryDays = useCallback(
    (d: number) => {
      const next = { ...state, itineraryDays: Math.min(14, Math.max(1, d)), updatedAt: Date.now() };
      setState(next);
      persistState(next);
      setItineraryData(null);
    },
    [state, persistState]
  );

  if (loading) {
    return (
      <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
        <div className="rounded-2xl bg-light-secondary dark:bg-dark-secondary p-8 animate-pulse">
          <div className="h-6 w-48 bg-light-200 dark:bg-dark-200 rounded mb-4" />
          <div className="h-4 w-32 bg-light-200 dark:bg-dark-200 rounded" />
        </div>
      </div>
    );
  }

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40">
      <div
        className={cn(
          'w-full max-w-2xl rounded-2xl shadow-xl',
          'bg-light-secondary dark:bg-dark-secondary border border-light-200/20 dark:border-dark-200/20',
          'overflow-hidden'
        )}
      >
        <div className="flex items-center justify-between p-4 border-b border-light-200/20 dark:border-dark-200/20">
          <h2 className="text-lg font-semibold">Plan your trip</h2>
          <button
            onClick={onClose}
            className="p-2 rounded-lg hover:bg-light-200/50 dark:hover:bg-dark-200/50 transition"
            aria-label="Close"
          >
            <X size={20} />
          </button>
        </div>

        <div className="flex gap-1 p-4 overflow-x-auto">
          {STEPS.map((s, i) => {
            const Icon = s.icon;
            const isActive = s.id === state.step;
            const isDone = i < stepIndex;
            return (
              <button
                key={s.id}
                onClick={() => goTo(s.id)}
                className={cn(
                  'flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm whitespace-nowrap transition',
                  isActive && 'bg-[#EA580C]/20 text-[#EA580C]',
                  isDone && !isActive && 'text-black/60 dark:text-white/60',
                  !isActive && !isDone && 'text-black/40 dark:text-white/40 hover:bg-light-200/50 dark:hover:bg-dark-200/50'
                )}
              >
                <Icon size={16} />
                {s.label}
              </button>
            );
          })}
        </div>

        <div className="p-6 min-h-[200px]">
          {state.step === 'search' && (
            <div>
              <label className="block text-sm font-medium mb-2">Where would you like to go?</label>
              <input
                type="text"
                value={state.searchQuery}
                onChange={(e) => updateSearch(e.target.value)}
                placeholder="e.g. Paris, Japan, Iceland"
                className={cn(
                  'w-full px-4 py-3 rounded-xl border',
                  'bg-light-primary dark:bg-dark-primary border-light-200 dark:border-dark-200',
                  'focus:outline-none focus:ring-2 focus:ring-[#EA580C]/50'
                )}
                autoFocus
              />
            </div>
          )}
          {state.step === 'places' && (
            <div>
              <p className="text-black/60 dark:text-white/60 text-sm">
                Places step — search results for &quot;{state.searchQuery || '...'}&quot; will appear here.
              </p>
              <p className="text-sm mt-2 text-black/40 dark:text-white/40">
                Coming soon: integration with search and map APIs.
              </p>
            </div>
          )}
          {state.step === 'route' && (
            <div>
              <div className="flex items-center gap-3 mb-4">
                <label className="text-sm font-medium">Duration:</label>
                <select
                  value={state.itineraryDays ?? 3}
                  onChange={(e) => updateItineraryDays(parseInt(e.target.value, 10))}
                  className="px-3 py-2 rounded-lg border bg-light-primary dark:bg-dark-primary border-light-200 dark:border-dark-200 text-sm"
                >
                  {[1, 3, 5, 7, 10, 14].map((d) => (
                    <option key={d} value={d}>{d} day{d > 1 ? 's' : ''}</option>
                  ))}
                </select>
                <span className="text-black/50 dark:text-white/50 text-sm">
                  for &quot;{state.searchQuery || '...'}&quot;
                </span>
              </div>
              {itineraryLoading ? (
                <div className="space-y-3 animate-pulse">
                  <div className="h-4 w-3/4 bg-light-200 dark:bg-dark-200 rounded" />
                  <div className="h-3 w-full bg-light-200 dark:bg-dark-200 rounded" />
                  <div className="h-3 w-2/3 bg-light-200 dark:bg-dark-200 rounded" />
                </div>
              ) : itineraryError ? (
                <div>
                  <p className="text-sm text-red-600 dark:text-red-400">{itineraryError}</p>
                  <button
                    type="button"
                    onClick={() => {
                      setItineraryError(null);
                      setItineraryLoading(true);
                      fetchItinerary(state.searchQuery, state.itineraryDays ?? 3)
                        .then((data) => {
                          if (data) setItineraryData(data);
                          else setItineraryError('Could not generate itinerary.');
                        })
                        .catch(() => setItineraryError('Request failed. Try again.'))
                        .finally(() => setItineraryLoading(false));
                    }}
                    className="mt-2 text-sm text-[#EA580C] hover:underline"
                  >
                    Retry
                  </button>
                </div>
              ) : itineraryData?.days?.length ? (
                <div className="space-y-4 max-h-[280px] overflow-y-auto">
                  {itineraryData.summary && (
                    <p className="text-sm text-black/70 dark:text-white/70">{itineraryData.summary}</p>
                  )}
                  {itineraryData.days.map((d) => (
                    <div
                      key={d.day}
                      className="p-3 rounded-xl bg-light-primary dark:bg-dark-primary border border-light-200/50 dark:border-dark-200/50"
                    >
                      <h4 className="font-medium text-sm">{d.title}</h4>
                      <ul className="mt-2 space-y-1 text-sm text-black/70 dark:text-white/70">
                        {d.activities.map((a, i) => (
                          <li key={i}>• {a}</li>
                        ))}
                      </ul>
                      {d.tips && (
                        <p className="mt-2 text-xs text-[#EA580C]">{d.tips}</p>
                      )}
                    </div>
                  ))}
                </div>
              ) : (
                <p className="text-sm text-black/50 dark:text-white/50">
                  Enter a destination in the Search step first, then return here.
                </p>
              )}
            </div>
          )}
          {state.step === 'hotels' && (
            <div>
              <p className="text-black/60 dark:text-white/60 text-sm">Hotels — Tripadvisor and Selfbook integration.</p>
              <p className="text-sm mt-2 text-black/40 dark:text-white/40">Coming soon: hotel recommendations.</p>
            </div>
          )}
          {state.step === 'tickets' && (
            <div>
              <p className="text-black/60 dark:text-white/60 text-sm">Tickets — flight and transport options.</p>
              <p className="text-sm mt-2 text-black/40 dark:text-white/40">Coming soon: booking integration.</p>
            </div>
          )}
        </div>

        <div className="flex items-center justify-between p-4 border-t border-light-200/20 dark:border-dark-200/20">
          <button
            onClick={goPrev}
            disabled={!canPrev}
            className={cn(
              'flex items-center gap-1 px-4 py-2 rounded-lg text-sm font-medium transition',
              canPrev
                ? 'hover:bg-light-200/50 dark:hover:bg-dark-200/50'
                : 'opacity-40 cursor-not-allowed'
            )}
          >
            <ChevronLeft size={18} />
            Back
          </button>
          {saving && <span className="text-xs text-black/40 dark:text-white/40">Saving...</span>}
          <button
            onClick={goNext}
            disabled={!canNext}
            className={cn(
              'flex items-center gap-1 px-4 py-2 rounded-lg text-sm font-medium bg-[#EA580C] text-white transition hover:opacity-90',
              !canNext && 'opacity-50 cursor-not-allowed'
            )}
          >
            Next
            <ChevronRight size={18} />
          </button>
        </div>
      </div>
    </div>
  );
}
