import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';
import { COMPARISON_PRESETS } from '../data/courseComparisonData';
import { findCourseBySlug, COURSES } from '../data/courses';

interface ComparisonContextType {
  selectedSlugs: string[];
  drawerOpen: boolean;
  setDrawerOpen: (open: boolean) => void;
  addCourse: (slug: string) => boolean;
  removeCourse: (slug: string) => void;
  toggleCourse: (slug: string) => void;
  clearAll: () => void;
  isInComparison: (slug: string) => boolean;
  loadPreset: (presetId: string) => void;
  canAddMore: boolean;
  limitNotice: string | null;
  dismissLimitNotice: () => void;
}

const ComparisonContext = createContext<ComparisonContextType | undefined>(undefined);

const STORAGE_KEY = 'pania_compared_courses';

/** Validates that slugs exist in catalogue and returns unique array up to max 3 */
function validateSlugs(slugs: unknown[]): string[] {
  if (!Array.isArray(slugs)) return [];
  const unique = Array.from(new Set(slugs.filter((s): s is string => typeof s === 'string')));
  return unique
    .filter((slug) => Boolean(findCourseBySlug(slug)))
    .slice(0, 3);
}

export function ComparisonProvider({ children }: { children: React.ReactNode }) {
  // 1. Initial State: Start new visitors with NO preselected courses.
  // Validate any existing localStorage entries against catalogue.
  const [selectedSlugs, setSelectedSlugs] = useState<string[]>(() => {
    try {
      // First priority: Check if URL already has a ?compare= parameter
      const hash = typeof window !== 'undefined' ? window.location.hash : '';
      const queryIdx = hash.indexOf('?');
      if (queryIdx !== -1) {
        const params = new URLSearchParams(hash.slice(queryIdx));
        const compareParam = params.get('compare');
        if (compareParam) {
          const urlSlugs = validateSlugs(compareParam.split(','));
          if (urlSlugs.length > 0) {
            return urlSlugs;
          }
        }
      }

      // Second: Read from localStorage if explicitly set previously
      const saved = localStorage.getItem(STORAGE_KEY);
      if (saved !== null) {
        const parsed = JSON.parse(saved);
        return validateSlugs(parsed);
      }
    } catch {
      // fallback safe
    }

    // Default: Empty for new visitors
    return [];
  });

  const [drawerOpen, setDrawerOpen] = useState<boolean>(() => {
    // If URL had compare parameter on initial load, auto-open drawer
    try {
      const hash = typeof window !== 'undefined' ? window.location.hash : '';
      return hash.includes('compare=');
    } catch {
      return false;
    }
  });

  const [limitNotice, setLimitNotice] = useState<string | null>(null);

  // Sync to localStorage
  useEffect(() => {
    try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(selectedSlugs));
    } catch {
      // ignore
    }
  }, [selectedSlugs]);

  // Listen to URL hash change for compare parameter
  useEffect(() => {
    const handleHashChange = () => {
      try {
        const hash = window.location.hash;
        const queryIdx = hash.indexOf('?');
        if (queryIdx !== -1) {
          const params = new URLSearchParams(hash.slice(queryIdx));
          const compareParam = params.get('compare');
          if (compareParam) {
            const valid = validateSlugs(compareParam.split(','));
            if (valid.length > 0) {
              setSelectedSlugs(valid);
              setDrawerOpen(true);
            }
          }
        }
      } catch {
        // ignore
      }
    };

    window.addEventListener('hashchange', handleHashChange);
    return () => window.removeEventListener('hashchange', handleHashChange);
  }, []);

  const dismissLimitNotice = useCallback(() => {
    setLimitNotice(null);
  }, []);

  const addCourse = useCallback((slug: string): boolean => {
    // Validate course exists
    if (!findCourseBySlug(slug)) return false;

    if (selectedSlugs.includes(slug)) return false;

    if (selectedSlugs.length >= 3) {
      // Never silently replace! Explain limit clearly to the user
      setLimitNotice('Comparison is limited to 3 courses. Please remove an existing track to add another.');
      return false;
    }

    setLimitNotice(null);
    setSelectedSlugs((prev) => [...prev, slug]);
    return true;
  }, [selectedSlugs]);

  const removeCourse = useCallback((slug: string) => {
    setSelectedSlugs((prev) => prev.filter((s) => s !== slug));
    setLimitNotice(null);
  }, []);

  const toggleCourse = useCallback((slug: string) => {
    if (!findCourseBySlug(slug)) return;

    if (selectedSlugs.includes(slug)) {
      removeCourse(slug);
    } else {
      if (selectedSlugs.length >= 3) {
        // Never silently replace!
        setLimitNotice('Comparison is limited to 3 courses. Please remove an existing track to add another.');
      } else {
        setLimitNotice(null);
        setSelectedSlugs((prev) => [...prev, slug]);
      }
    }
  }, [selectedSlugs, removeCourse]);

  const clearAll = useCallback(() => {
    setSelectedSlugs([]);
    setLimitNotice(null);
  }, []);

  const isInComparison = useCallback((slug: string): boolean => {
    return selectedSlugs.includes(slug);
  }, [selectedSlugs]);

  const loadPreset = useCallback((presetId: string) => {
    const preset = COMPARISON_PRESETS.find((p) => p.id === presetId);
    if (preset) {
      const valid = validateSlugs(preset.slugs);
      setSelectedSlugs(valid);
      setLimitNotice(null);
      setDrawerOpen(true);
    }
  }, []);

  return (
    <ComparisonContext.Provider
      value={{
        selectedSlugs,
        drawerOpen,
        setDrawerOpen,
        addCourse,
        removeCourse,
        toggleCourse,
        clearAll,
        isInComparison,
        loadPreset,
        canAddMore: selectedSlugs.length < 3,
        limitNotice,
        dismissLimitNotice,
      }}
    >
      {children}
    </ComparisonContext.Provider>
  );
}

export function useComparison() {
  const context = useContext(ComparisonContext);
  if (!context) {
    throw new Error('useComparison must be used within a ComparisonProvider');
  }
  return context;
}
