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

export interface CookieConsent {
    essential: boolean; // Always true
    preferences: boolean; // Theme, UI preferences
    analytics: boolean; // Measurement / analytics
}

interface CookieContextType {
    consent: CookieConsent;
    updateConsent: (newConsent: CookieConsent) => void;
    acceptAll: () => void;
    rejectAll: () => void;
    hasInteracted: boolean; // True if user has made a choice
    showBanner: boolean;
    closeBanner: () => void;
}

const CONSENT_COOKIE_NAME = 'xeewy_cookie_consent';
const CONSENT_COOKIE_MAX_AGE_DAYS = 180;

const defaultConsent: CookieConsent = {
    essential: true,
    preferences: false,
    analytics: false,
};

const getCookie = (name: string): string | null => {
    const prefix = `${name}=`;
    const parts = document.cookie.split(';').map((part) => part.trim());
    const found = parts.find((part) => part.startsWith(prefix));
    if (!found) return null;
    return found.slice(prefix.length);
};

const setCookie = (name: string, value: string, days: number) => {
    const maxAge = days * 24 * 60 * 60;
    const securePart = window.location.protocol === 'https:' ? '; Secure' : '';
    document.cookie = `${name}=${value}; Max-Age=${maxAge}; Path=/; SameSite=Lax${securePart}`;
};

const removeCookie = (name: string) => {
    const securePart = window.location.protocol === 'https:' ? '; Secure' : '';
    document.cookie = `${name}=; Max-Age=0; Path=/; SameSite=Lax${securePart}`;
};

const CookieContext = createContext<CookieContextType | undefined>(undefined);

export const CookieProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
    const [consent, setConsent] = useState<CookieConsent>(defaultConsent);
    const [hasInteracted, setHasInteracted] = useState(false);
    const [showBanner, setShowBanner] = useState(false);

    const signConsent = async (rawConsent: CookieConsent) => {
        const response = await fetch('/api/cookies/sign-consent', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                consent: {
                    essential: true,
                    preferences: Boolean(rawConsent.preferences),
                    analytics: Boolean(rawConsent.analytics)
                }
            })
        });

        const payload = (await response.json().catch(() => null)) as { token?: string; message?: string } | null;
        if (!response.ok || !payload?.token) {
            throw new Error(payload?.message || 'Unable to sign consent.');
        }
        return payload.token;
    };

    const verifyConsentToken = async (token: string) => {
        const response = await fetch('/api/cookies/verify-consent', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ token })
        });

        const payload = (await response.json().catch(() => null)) as {
            consent?: Partial<CookieConsent>;
            message?: string;
        } | null;

        if (!response.ok || !payload?.consent) {
            return null;
        }
        return {
            ...defaultConsent,
            ...payload.consent,
            essential: true
        } as CookieConsent;
    };

    useEffect(() => {
        const savedConsent = getCookie(CONSENT_COOKIE_NAME);
        const bootstrapConsent = async () => {
            if (!savedConsent) {
                setShowBanner(true);
                return;
            }

            const verified = await verifyConsentToken(savedConsent);
            if (!verified) {
                removeCookie(CONSENT_COOKIE_NAME);
                setConsent(defaultConsent);
                setHasInteracted(false);
                setShowBanner(true);
                return;
            }

            setConsent(verified);
            setHasInteracted(true);
            setShowBanner(false);
        };

        void bootstrapConsent();
    }, []);

    const saveConsent = async (newConsent: CookieConsent) => {
        try {
            const token = await signConsent(newConsent);
            setCookie(CONSENT_COOKIE_NAME, token, CONSENT_COOKIE_MAX_AGE_DAYS);
            setConsent(newConsent);
            setHasInteracted(true);
            setShowBanner(false);
        } catch {
            // Keep banner visible if signing fails
            setShowBanner(true);
        }
    };

    const updateConsent = (newConsent: CookieConsent) => {
        void saveConsent({ ...newConsent, essential: true });
    };

    const acceptAll = () => {
        void saveConsent({
            essential: true,
            preferences: true,
            analytics: true,
        });
    };

    const rejectAll = () => {
        void saveConsent({
            essential: true,
            preferences: false,
            analytics: false,
        });
    };

    const closeBanner = () => {
        setShowBanner(false);
    };

    return (
        <CookieContext.Provider value={{
            consent,
            updateConsent,
            acceptAll,
            rejectAll,
            hasInteracted,
            showBanner,
            closeBanner
        }}>
            {children}
        </CookieContext.Provider>
    );
};

export const useCookie = () => {
    const context = useContext(CookieContext);
    if (!context) {
        throw new Error('useCookie must be used within a CookieProvider');
    }
    return context;
};
