import React, {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from 'react';

const CONSENT_STORAGE_KEY = 'fotospiel.consent';
const CONSENT_VERSION = '2025-10-17-1';

export type ConsentCategory = 'functional' | 'analytics';

export type ConsentPreferences = Record<ConsentCategory, boolean>;

interface StoredConsent {
  version: string;
  preferences: ConsentPreferences;
  decisionMade: boolean;
  updatedAt: string | null;
}

const defaultPreferences: ConsentPreferences = {
  functional: true,
  analytics: false,
};

const defaultState: StoredConsent = {
  version: CONSENT_VERSION,
  preferences: { ...defaultPreferences },
  decisionMade: false,
  updatedAt: null,
};

interface ConsentContextValue {
  preferences: ConsentPreferences;
  decisionMade: boolean;
  showBanner: boolean;
  acceptAll: () => void;
  rejectAll: () => void;
  savePreferences: (preferences: Partial<ConsentPreferences>) => void;
  hasConsent: (category: ConsentCategory) => boolean;
  openPreferences: () => void;
  closePreferences: () => void;
  isPreferencesOpen: boolean;
}

const ConsentContext = createContext<ConsentContextValue | undefined>(undefined);

function normalizeState(state: StoredConsent | null): StoredConsent {
  if (!state || state.version !== CONSENT_VERSION) {
    return { ...defaultState };
  }

  return {
    version: CONSENT_VERSION,
    decisionMade: state.decisionMade ?? false,
    updatedAt: state.updatedAt ?? null,
    preferences: {
      ...defaultPreferences,
      ...state.preferences,
      functional: true,
    },
  };
}

function getInitialState(): StoredConsent {
  if (typeof window === 'undefined') {
    return { ...defaultState };
  }

  try {
    const raw = window.localStorage.getItem(CONSENT_STORAGE_KEY);
    if (!raw) {
      return { ...defaultState };
    }

    const parsed = JSON.parse(raw) as StoredConsent;
    return normalizeState(parsed);
  } catch {
    return { ...defaultState };
  }
}

export const ConsentProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [state, setState] = useState<StoredConsent>(() => getInitialState());
  const [isPreferencesOpen, setPreferencesOpen] = useState(false);

  useEffect(() => {
    if (typeof window === 'undefined') {
      return;
    }

    window.localStorage.setItem(CONSENT_STORAGE_KEY, JSON.stringify(state));
  }, [state]);

  const acceptAll = useCallback(() => {
    setState({
      version: CONSENT_VERSION,
      preferences: { functional: true, analytics: true },
      decisionMade: true,
      updatedAt: new Date().toISOString(),
    });
    setPreferencesOpen(false);
  }, []);

  const rejectAll = useCallback(() => {
    setState({
      version: CONSENT_VERSION,
      preferences: { functional: true, analytics: false },
      decisionMade: true,
      updatedAt: new Date().toISOString(),
    });
    setPreferencesOpen(false);
  }, []);

  const savePreferences = useCallback((preferences: Partial<ConsentPreferences>) => {
    setState((prev) => ({
      version: CONSENT_VERSION,
      preferences: {
        ...defaultPreferences,
        ...prev.preferences,
        ...preferences,
        functional: true,
      },
      decisionMade: true,
      updatedAt: new Date().toISOString(),
    }));
    setPreferencesOpen(false);
  }, []);

  const hasConsent = useCallback(
    (category: ConsentCategory) => {
      return Boolean(state.preferences?.[category]);
    },
    [state.preferences],
  );

  const openPreferences = useCallback(() => {
    setPreferencesOpen(true);
  }, []);

  const closePreferences = useCallback(() => {
    setPreferencesOpen(false);
  }, []);

  const value = useMemo<ConsentContextValue>(
    () => ({
      preferences: state.preferences,
      decisionMade: state.decisionMade,
      showBanner: !state.decisionMade,
      acceptAll,
      rejectAll,
      savePreferences,
      hasConsent,
      openPreferences,
      closePreferences,
      isPreferencesOpen,
    }),
    [
      state.preferences,
      state.decisionMade,
      acceptAll,
      rejectAll,
      savePreferences,
      hasConsent,
      openPreferences,
      closePreferences,
      isPreferencesOpen,
    ],
  );

  return <ConsentContext.Provider value={value}>{children}</ConsentContext.Provider>;
};

export const useConsent = (): ConsentContextValue => {
  const context = useContext(ConsentContext);

  if (!context) {
    throw new Error('useConsent must be used within a ConsentProvider');
  }

  return context;
};
