import React, {
    createContext,
    useCallback,
    useContext,
    useEffect,
    useMemo,
    useRef,
    useState,
} from 'react';
import { apiFetch } from '@/lib/api';
import { mergeSequenceIntoContacts } from '@/lib/mergeSequenceIntoContacts';

const GeneratorWorkflowContext = createContext(null);

export function GeneratorWorkflowProvider({ children }) {
    const [step, setStep] = useState(1);
    const [uploadedFile, setUploadedFile] = useState(null);
    const [selectedProducts, setSelectedProducts] = useState([]);
    const [prompts, setPrompts] = useState({});
    const [linkedinPrompts, setLinkedinPrompts] = useState({});
    const [includeLinkedin, setIncludeLinkedin] = useState(false);
    const [isGenerating, setIsGenerating] = useState(false);
    const [generationComplete, setGenerationComplete] = useState(false);
    const [generationRunId, setGenerationRunId] = useState(0);
    const [genPhase, setGenPhase] = useState('email');
    const [contacts, setContacts] = useState([]);
    const [sequences, setSequences] = useState([]);
    const [progress, setProgress] = useState(0);
    const [streamComplete, setStreamComplete] = useState(false);
    const [reconnectKey, setReconnectKey] = useState(0);

    const prevRunIdRef = useRef(null);
    const eventSourceRef = useRef(null);

    const resetWorkflow = useCallback(() => {
        if (eventSourceRef.current) {
            eventSourceRef.current.close();
            eventSourceRef.current = null;
        }
        setStep(1);
        setUploadedFile(null);
        setSelectedProducts([]);
        setPrompts({});
        setLinkedinPrompts({});
        setIncludeLinkedin(false);
        setIsGenerating(false);
        setGenerationComplete(false);
        setGenerationRunId(0);
        setGenPhase('email');
        setContacts([]);
        setSequences([]);
        setProgress(0);
        setStreamComplete(false);
        prevRunIdRef.current = null;
    }, []);

    const beginGeneration = useCallback((runIdIncrement = true) => {
        setStreamComplete(false);
        setGenerationComplete(false);
        setContacts([]);
        setSequences([]);
        setProgress(0);
        setGenPhase('email');
        setIsGenerating(true);
        if (runIdIncrement) {
            setGenerationRunId((r) => r + 1);
        }
    }, []);

    const contactCount = uploadedFile?.contactCount || 0;

    useEffect(() => {
        if (!isGenerating || !uploadedFile?.fileId) return;

        const isNewRun = prevRunIdRef.current !== generationRunId;
        if (isNewRun) {
            prevRunIdRef.current = generationRunId;
            setContacts([]);
            setSequences([]);
            setProgress(0);
            setStreamComplete(false);
        }

        const reset = isNewRun ? 1 : 0;
        const url = `/api/generate-sequences?file_id=${encodeURIComponent(uploadedFile.fileId)}&reset=${reset}`;
        const eventSource = new EventSource(url);
        eventSourceRef.current = eventSource;

        eventSource.onmessage = (event) => {
            try {
                const data = JSON.parse(event.data);
                if (data.type === 'sequence') {
                    const seq = data.sequence;
                    setSequences((prev) => {
                        const sig = `${seq.id}-${seq.emailNumber}-${seq.channel || 'email'}-${seq.stepOrder ?? ''}`;
                        if (
                            prev.some(
                                (s) =>
                                    `${s.id}-${s.emailNumber}-${s.channel || 'email'}-${s.stepOrder ?? ''}` === sig
                            )
                        ) {
                            return prev;
                        }
                        return [...prev, seq];
                    });
                    setContacts((prev) => mergeSequenceIntoContacts(prev, seq));
                } else if (data.type === 'progress') {
                    if (typeof data.progress === 'number') setProgress(data.progress);
                } else if (data.type === 'phase') {
                    if (data.phase === 'linkedin') setGenPhase('linkedin');
                } else if (data.type === 'complete') {
                    setStreamComplete(true);
                    setIsGenerating(false);
                    setGenerationComplete(true);
                    eventSource.close();
                    eventSourceRef.current = null;
                } else if (data.type === 'error') {
                    console.error('Generation error:', data.error);
                    alert('Error generating sequences: ' + data.error);
                    eventSource.close();
                    eventSourceRef.current = null;
                    setIsGenerating(false);
                }
            } catch (err) {
                console.error('Error parsing SSE data:', err);
            }
        };

        eventSource.onerror = () => {
            eventSource.close();
            eventSourceRef.current = null;
            if (!streamComplete) setReconnectKey((k) => k + 1);
        };

        return () => {
            eventSource.close();
            if (eventSourceRef.current === eventSource) eventSourceRef.current = null;
        };
    }, [isGenerating, uploadedFile?.fileId, generationRunId]);

    useEffect(() => {
        if (!isGenerating || !uploadedFile?.fileId || reconnectKey === 0) return;
        let cancelled = false;
        (async () => {
            try {
                const [statusRes, seqRes] = await Promise.all([
                    apiFetch(`/api/generation-status?file_id=${encodeURIComponent(uploadedFile.fileId)}`),
                    apiFetch(`/api/sequences?file_id=${encodeURIComponent(uploadedFile.fileId)}`),
                ]);
                if (cancelled) return;
                if (statusRes.ok && seqRes.ok) {
                    const status = await statusRes.json();
                    const { sequences: list } = await seqRes.json();
                    if (status.is_complete) {
                        setStreamComplete(true);
                        setIsGenerating(false);
                        setGenerationComplete(true);
                    }
                    if (list?.length > 0) {
                        const byContact = new Map();
                        list.forEach((seq) => {
                            const key = seq.email;
                            const ch = seq.channel || 'email';
                            if (!byContact.has(key)) {
                                byContact.set(key, {
                                    id: seq.id,
                                    firstName: seq.firstName,
                                    lastName: seq.lastName,
                                    email: seq.email,
                                    company: seq.company,
                                    title: seq.title,
                                    product: seq.product,
                                    emails: [],
                                    linkedin: [],
                                });
                            }
                            const row = {
                                emailNumber: seq.emailNumber,
                                subject: seq.subject,
                                emailContent: seq.emailContent,
                                channel: ch,
                                stepOrder: seq.stepOrder,
                            };
                            const dedupe = (e) =>
                                e.stepOrder != null
                                    ? `ord-${e.stepOrder}-${ch}`
                                    : `${ch}-${e.emailNumber}`;
                            const rowKey = dedupe(row);
                            const c = byContact.get(key);
                            if (ch === 'linkedin') {
                                if (!c.linkedin.some((e) => dedupe(e) === rowKey)) {
                                    c.linkedin.push(row);
                                }
                            } else {
                                if (!c.emails.some((e) => dedupe(e) === rowKey)) {
                                    c.emails.push(row);
                                }
                            }
                        });
                        const arr = [...byContact.values()];
                        arr.sort((a, b) => (a.id || 0) - (b.id || 0));
                        setSequences(list);
                        setContacts(arr);
                        if (status.total_contacts > 0) {
                            const exp =
                                status.campaign_sequence_actions && status.total_contacts > 0
                                    ? status.total_contacts * status.campaign_sequence_actions
                                    : status.has_linkedin_prompts
                                      ? status.total_contacts * 2
                                      : status.total_contacts;
                            setProgress(
                                Math.min(100, ((status.completed_count || 0) / exp) * 100)
                            );
                        }
                    }
                }
            } catch (e) {
                if (!cancelled) console.error('Reconnect fetch error:', e);
            }
        })();
        return () => {
            cancelled = true;
        };
    }, [reconnectKey, isGenerating, uploadedFile?.fileId, contactCount]);

    useEffect(() => {
        if (!isGenerating || !uploadedFile?.fileId) return;
        const onVisible = () => {
            if (document.visibilityState === 'visible') setReconnectKey((k) => k + 1);
        };
        document.addEventListener('visibilitychange', onVisible);
        return () => document.removeEventListener('visibilitychange', onVisible);
    }, [isGenerating, uploadedFile?.fileId]);

    const value = useMemo(
        () => ({
            step,
            setStep,
            uploadedFile,
            setUploadedFile,
            selectedProducts,
            setSelectedProducts,
            prompts,
            setPrompts,
            linkedinPrompts,
            setLinkedinPrompts,
            includeLinkedin,
            setIncludeLinkedin,
            isGenerating,
            generationComplete,
            generationRunId,
            beginGeneration,
            setIsGenerating,
            setGenerationComplete,
            resetWorkflow,
            contacts,
            sequences,
            progress,
            genPhase,
            streamComplete,
            contactCount,
        }),
        [
            step,
            uploadedFile,
            selectedProducts,
            prompts,
            linkedinPrompts,
            includeLinkedin,
            isGenerating,
            generationComplete,
            generationRunId,
            beginGeneration,
            resetWorkflow,
            contacts,
            sequences,
            progress,
            genPhase,
            streamComplete,
            contactCount,
        ]
    );

    return (
        <GeneratorWorkflowContext.Provider value={value}>{children}</GeneratorWorkflowContext.Provider>
    );
}

export function useGeneratorWorkflow() {
    const ctx = useContext(GeneratorWorkflowContext);
    if (!ctx) {
        throw new Error('useGeneratorWorkflow must be used within GeneratorWorkflowProvider');
    }
    return ctx;
}
