import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { apiFetch } from '@/lib/api';
import { mergeSequenceIntoContacts } from '@/lib/mergeSequenceIntoContacts';
import { createPortal } from 'react-dom';
import {
    X,
    Upload,
    ArrowRight,
    ArrowLeft,
    Sparkles,
    Loader2,
    CheckCircle2,
    Search,
    Filter,
    Mail,
    UserPlus,
    MessageCircle,
    Clock,
    ChevronRight,
} from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Progress } from '@/components/ui/progress';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { cn } from '@/lib/utils';
import CampaignSequenceBuilder, { createDefaultSequenceSteps } from '@/components/campaigns/CampaignSequenceBuilder';
import ProductSelector from '@/components/products/ProductSelector';
import PromptEditor, {
    DEFAULT_TEMPLATES,
    LINKEDIN_DEFAULT_TEMPLATES,
} from '@/components/prompts/PromptEditor';
import SequenceCard from '@/components/sequences/SequenceCard';

const STEPS = [
    { id: 1, label: 'Upload & Select' },
    { id: 2, label: 'Configure Sequence' },
    { id: 3, label: 'Generate Contents' },
    { id: 4, label: 'Review & Launch' },
];

const WIZARD_SEQUENCE_TAG = '🔒 CAMPAIGN WIZARD — SEQUENCE';

function estimateCsvRows(file) {
    if (!file) return 0;
    return new Promise((resolve) => {
        const reader = new FileReader();
        reader.onload = (e) => {
            const text = String(e.target?.result || '');
            const lines = text.split(/\r?\n/).filter((line) => line.trim().length > 0);
            resolve(Math.max(0, lines.length - 1));
        };
        reader.onerror = () => resolve(0);
        reader.readAsText(file.slice(0, Math.min(file.size, 512 * 1024)));
    });
}

function mailboxLabelForAppendixStep(step, mailboxDefaults) {
    if (step.channel !== 'gmail' || !mailboxDefaults) return '';
    const ref =
        step.unipile_account_ref_id ?? mailboxDefaults.default_mailbox_unipile_account_ref_id ?? null;
    if (ref == null) return '';
    const a = (mailboxDefaults.accounts || []).find((x) => Number(x.id) === Number(ref));
    return ((a?.display_name || a?.label || '') || '').trim();
}

function buildCampaignSequenceAppendix(steps, mailboxDefaults = null, parallelTracks = false) {
    const lines = [
        WIZARD_SEQUENCE_TAG,
        '(AUTHORITATIVE — OVERRIDES ANY FIXED “N EMAILS” OR “N MESSAGES” COUNT IN THIS PROMPT)',
        '',
        'The campaign sequence is fixed. Generate content only for the channels below; the system maps rows to Gmail vs LinkedIn.',
        'Respect wait steps as pacing context between touches (do not invent extra touches for waits).',
        '',
    ];
    if (parallelTracks) {
        lines.push(
            'Execution note: Gmail and LinkedIn run on separate timelines — a wait after an email does not delay LinkedIn steps (and vice versa).',
            ''
        );
    }
    let n = 0;
    (steps || []).forEach((s) => {
        if (s.type === 'wait') {
            lines.push(`• Wait ${s.days ?? 1} day(s)`);
        }
        if (s.type === 'action') {
            n += 1;
            if (s.channel === 'gmail') {
                const mb = mailboxLabelForAppendixStep(s, mailboxDefaults);
                lines.push(
                    `${n}. Gmail — ${s.title || 'Email'}${mb ? ` (sending mailbox: ${mb})` : ''}`
                );
            } else if (s.channel === 'linkedin') {
                const kind =
                    s.action === 'linkedin_connect'
                        ? 'LinkedIn connection request (must be the first LinkedIn output before any DM)'
                        : 'LinkedIn DM / follow-up';
                lines.push(`${n}. ${kind} — ${s.title || ''}`);
            }
        }
    });
    lines.push(
        '',
        'LinkedIn: the first LinkedIn message in your output must be the connection request whenever the sequence includes a connection step before DMs.',
        'Write exactly one labeled LinkedIn message (Message i) per LinkedIn action listed above — same count and order; do not add extra LinkedIn messages beyond those actions.',
        'Keep narrative continuity with Gmail touches in the same campaign week where relevant.'
    );
    return lines.join('\n');
}

function progressFromGenerationStatus(st) {
    if (st?.is_complete) return 100;
    const total = st.total_contacts || 0;
    if (!total) return 0;
    const done = st.completed_count || 0;
    const exp =
        st.campaign_sequence_actions && total > 0
            ? total * st.campaign_sequence_actions
            : st.has_linkedin_prompts
              ? total * 2
              : total;
    return exp ? Math.min(100, Math.round((done / exp) * 100)) : 0;
}

function sequenceListToContacts(list) {
    let contacts = [];
    (list || []).forEach((row) => {
        contacts = mergeSequenceIntoContacts(contacts, {
            id: row.id,
            emailNumber: row.emailNumber,
            firstName: row.firstName,
            lastName: row.lastName,
            email: row.email,
            company: row.company,
            title: row.title,
            product: row.product,
            subject: row.subject,
            emailContent: row.emailContent,
            channel: row.channel || 'email',
            stepOrder: row.stepOrder != null ? row.stepOrder : undefined,
        });
    });
    contacts.sort((a, b) => (a.id || 0) - (b.id || 0));
    return contacts;
}

function WizardSequencePreview({
    contacts,
    sequences,
    isGenerating,
    generationComplete,
    generationStarted,
    progress,
    contactCount,
    selectedProducts,
    sequenceHasLinkedin,
    genPhase,
}) {
    const [searchQuery, setSearchQuery] = useState('');
    const [filterProduct, setFilterProduct] = useState('all');
    const [displayedCount, setDisplayedCount] = useState(50);

    useEffect(() => {
        setDisplayedCount(50);
    }, [searchQuery, filterProduct]);

    const filteredContacts = contacts.filter((contact) => {
        const matchesSearch =
            searchQuery === '' ||
            contact.firstName?.toLowerCase().includes(searchQuery.toLowerCase()) ||
            contact.lastName?.toLowerCase().includes(searchQuery.toLowerCase()) ||
            contact.company?.toLowerCase().includes(searchQuery.toLowerCase()) ||
            contact.email?.toLowerCase().includes(searchQuery.toLowerCase());
        const matchesFilter = filterProduct === 'all' || contact.product === filterProduct;
        return matchesSearch && matchesFilter;
    });
    const displayedContacts = filteredContacts.slice(0, displayedCount);
    const hasMore = filteredContacts.length > displayedCount;
    const showProgress =
        generationStarted && (isGenerating || !generationComplete);
    const phaseLabel =
        sequenceHasLinkedin && genPhase === 'linkedin' && isGenerating
            ? 'LinkedIn sequences'
            : 'Email sequences';

    return (
        <div className="w-full space-y-4">
            {generationStarted ? (
                <div className="mb-2 rounded-2xl border border-slate-200 bg-white p-6">
                    <div className="mb-4 flex items-center justify-between">
                        <div className="flex items-center gap-3">
                            {generationComplete ? (
                                <div className="rounded-xl bg-green-100 p-3">
                                    <CheckCircle2 className="h-6 w-6 text-green-600" />
                                </div>
                            ) : (
                                <div className="rounded-xl bg-violet-100 p-3">
                                    <Loader2 className="h-6 w-6 animate-spin text-violet-600" />
                                </div>
                            )}
                            <div>
                                <h3 className="font-semibold text-slate-800">
                                    {generationComplete ? 'Generation complete!' : `Generating ${phaseLabel}…`}
                                </h3>
                                <p className="text-sm text-slate-500">
                                    {contacts.length} contacts · {sequences.length} generated rows
                                    {contactCount ? ` · ~${contactCount} contacts in file` : ''}
                                </p>
                            </div>
                        </div>
                    </div>
                    {showProgress ? <Progress value={progress} className="h-2" /> : null}
                </div>
            ) : null}

            {sequences.length > 0 && (
                <div className="flex flex-col gap-3 sm:flex-row">
                    <div className="relative flex-1">
                        <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400" />
                        <Input
                            placeholder="Search contacts…"
                            value={searchQuery}
                            onChange={(e) => setSearchQuery(e.target.value)}
                            className="pl-10"
                        />
                    </div>
                    <Select value={filterProduct} onValueChange={setFilterProduct}>
                        <SelectTrigger className="w-full sm:w-48">
                            <Filter className="mr-2 h-4 w-4 text-slate-400" />
                            <SelectValue placeholder="Filter by product" />
                        </SelectTrigger>
                        <SelectContent>
                            <SelectItem value="all">All Products</SelectItem>
                            {selectedProducts.map((product) => (
                                <SelectItem key={product.id} value={product.name}>
                                    {product.name}
                                </SelectItem>
                            ))}
                        </SelectContent>
                    </Select>
                </div>
            )}

            <div className="custom-scrollbar max-h-[min(420px,50vh)] space-y-3 overflow-y-auto pr-1">
                {displayedContacts.map((contact, index) => (
                    <SequenceCard
                        key={contact.id || `${contact.firstName}-${contact.lastName}-${contact.email}`}
                        contact={contact}
                        index={index}
                    />
                ))}
                {hasMore && (
                    <div className="py-3 text-center">
                        <Button
                            type="button"
                            variant="outline"
                            onClick={() => setDisplayedCount((c) => Math.min(c + 50, filteredContacts.length))}
                        >
                            Load more ({filteredContacts.length - displayedCount} remaining)
                        </Button>
                    </div>
                )}
            </div>

            {!generationStarted && contacts.length === 0 && sequences.length === 0 && (
                <div className="rounded-xl border border-dashed border-slate-200 bg-slate-50/80 py-12 text-center text-sm text-slate-500">
                    Generated messages will appear here after you click Generate. You can continue to the next step
                    while generation runs in the background.
                </div>
            )}
        </div>
    );
}

function ReviewSequenceTimeline({ steps, parallelTracks }) {
    if (!steps?.length) {
        return <p className="text-sm text-slate-500">No sequence steps.</p>;
    }
    return (
        <div>
            {parallelTracks ? (
                <p className="mb-3 text-xs text-slate-600">
                    Parallel tracks: Gmail and LinkedIn advance on separate timers — waits only apply within the same
                    channel.
                </p>
            ) : null}
            <div className="flex flex-wrap items-center gap-1 py-2">
            {steps.map((s, i) => (
                <React.Fragment key={s.id || i}>
                    {i > 0 ? <ChevronRight className="mx-0.5 h-4 w-4 shrink-0 text-slate-300" /> : null}
                    {s.type === 'wait' ? (
                        <span className="inline-flex items-center gap-1 rounded-lg border border-dashed border-blue-200 bg-sky-50 px-2.5 py-1.5 text-xs font-medium text-slate-700">
                            <Clock className="h-3.5 w-3.5 text-blue-600" />
                            Wait {s.days ?? 1}d
                        </span>
                    ) : (
                        <span
                            className={cn(
                                'inline-flex max-w-[200px] items-center gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs font-medium',
                                s.channel === 'linkedin'
                                    ? 'border-sky-200 bg-sky-50 text-sky-900'
                                    : 'border-violet-200 bg-violet-50 text-violet-900'
                            )}
                        >
                            {s.action === 'linkedin_connect' ? (
                                <UserPlus className="h-3.5 w-3.5 shrink-0" />
                            ) : s.channel === 'linkedin' ? (
                                <MessageCircle className="h-3.5 w-3.5 shrink-0" />
                            ) : (
                                <Mail className="h-3.5 w-3.5 shrink-0" />
                            )}
                            <span className="truncate">{s.title || (s.channel === 'gmail' ? 'Email' : 'LinkedIn')}</span>
                        </span>
                    )}
                </React.Fragment>
            ))}
            </div>
        </div>
    );
}

export default function CreateCampaignWizard({
    open,
    onOpenChange,
    onComplete,
    onDraftPersist,
    initialCampaign = null,
}) {
    const [step, setStep] = useState(1);
    const [campaignName, setCampaignName] = useState('');
    const [prospectFile, setProspectFile] = useState(null);
    const [wizardUpload, setWizardUpload] = useState(null);
    const [uploadingCsv, setUploadingCsv] = useState(false);
    const [dragOver, setDragOver] = useState(false);
    const [estimatedContacts, setEstimatedContacts] = useState(0);
    const [sequenceSteps, setSequenceSteps] = useState(() => createDefaultSequenceSteps());
    const [parallelTracks, setParallelTracks] = useState(false);
    const [linkedinDefaults, setLinkedinDefaults] = useState(null);
    const [mailboxDefaults, setMailboxDefaults] = useState(null);

    const [selectedProducts, setSelectedProducts] = useState([]);
    const [prompts, setPrompts] = useState({});
    const [linkedinPrompts, setLinkedinPrompts] = useState({});

    const [genSequences, setGenSequences] = useState([]);
    const [genContacts, setGenContacts] = useState([]);
    const [genProgress, setGenProgress] = useState(0);
    const [genRunning, setGenRunning] = useState(false);
    const [genComplete, setGenComplete] = useState(false);
    const [genPhase, setGenPhase] = useState('email');
    const [genRunId, setGenRunId] = useState(0);
    const eventSourceRef = useRef(null);
    const promptEditorRef = useRef(null);
    const prevGenRunIdRef = useRef(null);
    const hydratedCampaignIdRef = useRef(null);
    const openRef = useRef(open);
    openRef.current = open;

    const sequenceHasLinkedin = useMemo(
        () =>
            sequenceSteps.some(
                (s) => s.type === 'action' && s.channel === 'linkedin' && s.action !== 'email'
            ),
        [sequenceSteps]
    );

    const reset = useCallback(() => {
        if (eventSourceRef.current) {
            eventSourceRef.current.close();
            eventSourceRef.current = null;
        }
        setStep(1);
        setCampaignName('');
        setProspectFile(null);
        setWizardUpload(null);
        setUploadingCsv(false);
        setEstimatedContacts(0);
        setDragOver(false);
        setSequenceSteps(createDefaultSequenceSteps());
        setParallelTracks(false);
        setSelectedProducts([]);
        setPrompts({});
        setLinkedinPrompts({});
        setGenSequences([]);
        setGenContacts([]);
        setGenProgress(0);
        setGenRunning(false);
        setGenComplete(false);
        setGenPhase('email');
        setGenRunId(0);
        prevGenRunIdRef.current = null;
    }, []);

    useEffect(() => {
        if (!open) {
            if (genRunning) return;
            reset();
        }
    }, [open, genRunning, reset]);

    /** Fresh "Create" session — clear any in-component state (including orphan streams). */
    useEffect(() => {
        if (open && !initialCampaign?.id) {
            reset();
        }
    }, [open, initialCampaign?.id, reset]);

    useEffect(() => {
        if (!open || !initialCampaign?.id) return;
        if (hydratedCampaignIdRef.current === initialCampaign.id) return;
        hydratedCampaignIdRef.current = initialCampaign.id;
        const incomingFile = initialCampaign.fileId || null;
        const currentFile = wizardUpload?.fileId ?? null;
        if (eventSourceRef.current) {
            const keepStream =
                !!incomingFile && !!currentFile && incomingFile === currentFile;
            if (!keepStream) {
                eventSourceRef.current.close();
                eventSourceRef.current = null;
            }
        }
        setGenSequences([]);
        setGenContacts([]);
        setGenRunId(0);
        prevGenRunIdRef.current = null;
        setCampaignName(initialCampaign.name || '');
        setProspectFile(null);
        if (initialCampaign.fileId) {
            setWizardUpload({
                fileId: initialCampaign.fileId,
                contactCount: initialCampaign.contacts ?? 0,
                name: initialCampaign.prospectFileName || '',
            });
        } else {
            setWizardUpload(null);
        }
        const seq = initialCampaign.sequence;
        if (Array.isArray(seq) && seq.length > 0) {
            setSequenceSteps(seq);
        } else {
            setSequenceSteps(createDefaultSequenceSteps());
        }
        setParallelTracks(!!initialCampaign.parallelTracks);
        setSelectedProducts(
            Array.isArray(initialCampaign.selectedProducts) ? initialCampaign.selectedProducts : []
        );
        setEstimatedContacts(initialCampaign.contacts || 0);
        setGenComplete(!!initialCampaign.generationComplete);
        setGenRunning(false);
        setGenProgress(initialCampaign.generationProgressPercent ?? 0);
        const ws =
            typeof initialCampaign.wizardStep === 'number'
                ? Math.min(4, Math.max(1, initialCampaign.wizardStep))
                : 1;
        setStep(ws);
        setPrompts(
            initialCampaign.wizardPrompts && typeof initialCampaign.wizardPrompts === 'object'
                ? { ...initialCampaign.wizardPrompts }
                : {}
        );
        setLinkedinPrompts(
            initialCampaign.wizardLinkedinPrompts &&
                typeof initialCampaign.wizardLinkedinPrompts === 'object'
                ? { ...initialCampaign.wizardLinkedinPrompts }
                : {}
        );
    }, [open, initialCampaign?.id, wizardUpload?.fileId]);

    useEffect(() => {
        if (!open || !wizardUpload?.fileId || !initialCampaign?.id) return;
        let cancelled = false;
        (async () => {
            try {
                const [stRes, seqRes] = await Promise.all([
                    apiFetch(`/api/generation-status?file_id=${encodeURIComponent(wizardUpload.fileId)}`),
                    apiFetch(`/api/sequences?file_id=${encodeURIComponent(wizardUpload.fileId)}`),
                ]);
                if (cancelled) return;
                if (seqRes.ok) {
                    const data = await seqRes.json();
                    const list = data.sequences || [];
                    setGenSequences(list);
                    setGenContacts(sequenceListToContacts(list));
                }
                if (stRes.ok) {
                    const st = await stRes.json();
                    if (!cancelled) {
                        setGenComplete(!!st.is_complete);
                        setGenProgress(progressFromGenerationStatus(st));
                    }
                }
            } catch (e) {
                if (!cancelled) console.error(e);
            }
        })();
        return () => {
            cancelled = true;
        };
    }, [open, wizardUpload?.fileId, initialCampaign?.id]);

    useEffect(() => {
        if (!open) hydratedCampaignIdRef.current = null;
    }, [open]);

    useEffect(() => {
        if (!prospectFile) {
            setEstimatedContacts(0);
            return;
        }
        let cancelled = false;
        estimateCsvRows(prospectFile).then((n) => {
            if (!cancelled) setEstimatedContacts(n);
        });
        return () => {
            cancelled = true;
        };
    }, [prospectFile]);

    useEffect(() => {
        if (!open) {
            setLinkedinDefaults(null);
            setMailboxDefaults(null);
            return;
        }
        let cancelled = false;
        Promise.allSettled([
            apiFetch('/api/unipile/linkedin/campaign-defaults').then((r) => r.json()),
            apiFetch('/api/unipile/mailbox/campaign-defaults').then((r) => r.json()),
        ]).then(([li, mb]) => {
            if (cancelled) return;
            setLinkedinDefaults(
                li.status === 'fulfilled'
                    ? li.value
                    : {
                          accounts: [],
                          linkedin_profile_display_name: '',
                          default_unipile_account_ref_id: null,
                      }
            );
            setMailboxDefaults(
                mb.status === 'fulfilled'
                    ? mb.value
                    : {
                          accounts: [],
                          mailbox_profile_display_name: '',
                          default_mailbox_unipile_account_ref_id: null,
                      }
            );
        });
        return () => {
            cancelled = true;
        };
    }, [open]);

    useEffect(() => {
        if (!linkedinDefaults) return;
        setSequenceSteps((prev) =>
            prev.map((s) => {
                if (s.type !== 'action' || s.channel !== 'linkedin') return s;
                const ref =
                    s.unipile_account_ref_id ?? linkedinDefaults.default_unipile_account_ref_id ?? null;
                const sender =
                    (s.sender_profile_name || '').trim() ||
                    (linkedinDefaults.linkedin_profile_display_name || '').trim();
                return {
                    ...s,
                    unipile_account_ref_id: ref,
                    sender_profile_name: sender,
                };
            })
        );
    }, [linkedinDefaults]);

    useEffect(() => {
        if (!mailboxDefaults) return;
        const accounts = mailboxDefaults.accounts || [];
        const fallbackId = accounts[0]?.id != null ? Number(accounts[0].id) : null;
        setSequenceSteps((prev) =>
            prev.map((s) => {
                if (s.type !== 'action' || s.channel !== 'gmail') return s;
                const ref =
                    s.unipile_account_ref_id ??
                    (mailboxDefaults.default_mailbox_unipile_account_ref_id != null
                        ? Number(mailboxDefaults.default_mailbox_unipile_account_ref_id)
                        : null) ??
                    fallbackId;
                return { ...s, unipile_account_ref_id: ref };
            })
        );
    }, [mailboxDefaults]);

    useEffect(() => {
        if (step !== 3 || selectedProducts.length === 0) return;
        const appendix = buildCampaignSequenceAppendix(sequenceSteps, mailboxDefaults, parallelTracks);
        setPrompts((prev) => {
            const next = { ...prev };
            let changed = false;
            selectedProducts.forEach((p) => {
                let cur = (next[p.name] || '').trim();
                if (!cur) {
                    cur = DEFAULT_TEMPLATES[p.name] || '';
                }
                if (!cur || cur.includes(WIZARD_SEQUENCE_TAG)) return;
                next[p.name] = `${cur}\n\n${appendix}`;
                changed = true;
            });
            return changed ? next : prev;
        });
        if (!sequenceHasLinkedin) return;
        setLinkedinPrompts((prev) => {
            const next = { ...prev };
            let changed = false;
            selectedProducts.forEach((p) => {
                let cur = (next[p.name] || '').trim();
                if (!cur) {
                    cur =
                        LINKEDIN_DEFAULT_TEMPLATES[p.name] ||
                        `🔒 LINKEDIN SYSTEM PROMPT\n\nYou write LinkedIn connection notes and DMs for ${p.name}. Message 1: peer-style connection only (~280 chars), no pitch; later messages add detail. Sign DMs with {{sender_name}}.\nMatch the Message count in the generation request exactly.`;
                }
                if (!cur || cur.includes(WIZARD_SEQUENCE_TAG)) return;
                next[p.name] = `${cur}\n\n${appendix}`;
                changed = true;
            });
            return changed ? next : prev;
        });
    }, [step, sequenceSteps, selectedProducts, sequenceHasLinkedin, mailboxDefaults, parallelTracks]);

    useEffect(() => {
        if (!genRunning || !wizardUpload?.fileId) return;

        const isNewRun = prevGenRunIdRef.current !== genRunId;
        if (isNewRun) {
            prevGenRunIdRef.current = genRunId;
            setGenSequences([]);
            setGenContacts([]);
            setGenProgress(0);
            setGenComplete(false);
            setGenPhase('email');
        }

        if (eventSourceRef.current) {
            eventSourceRef.current.close();
            eventSourceRef.current = null;
        }

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

        es.onmessage = (event) => {
            try {
                const data = JSON.parse(event.data);
                if (data.type === 'sequence') {
                    const seq = data.sequence;
                    setGenSequences((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];
                    });
                    setGenContacts((prev) => mergeSequenceIntoContacts(prev, seq));
                } else if (data.type === 'progress' && typeof data.progress === 'number') {
                    setGenProgress(data.progress);
                } else if (data.type === 'phase' && data.phase === 'linkedin') {
                    setGenPhase('linkedin');
                } else if (data.type === 'complete') {
                    setGenRunning(false);
                    setGenComplete(true);
                    es.close();
                    if (eventSourceRef.current === es) eventSourceRef.current = null;
                    if (!openRef.current) {
                        reset();
                    }
                } else if (data.type === 'error') {
                    console.error(data.error);
                    alert(`Generation error: ${data.error}`);
                    setGenRunning(false);
                    es.close();
                    if (eventSourceRef.current === es) eventSourceRef.current = null;
                    if (!openRef.current) {
                        reset();
                    }
                }
            } catch (e) {
                console.error(e);
            }
        };

        es.onerror = () => {
            es.close();
            if (eventSourceRef.current === es) eventSourceRef.current = null;
        };

        return () => {
            es.close();
            if (eventSourceRef.current === es) eventSourceRef.current = null;
        };
    }, [genRunning, wizardUpload?.fileId, genRunId]);

    const pickFile = async (file) => {
        if (!file) return;
        if (!file.name.toLowerCase().endsWith('.csv')) {
            alert('Please upload a .csv file (Apollo export), same as Email / AI Generator.');
            return;
        }
        setProspectFile(file);
        setWizardUpload(null);
        setUploadingCsv(true);
        try {
            const formData = new FormData();
            formData.append('file', file);
            const response = await apiFetch('/api/upload-csv', {
                method: 'POST',
                body: formData,
            });
            if (!response.ok) {
                throw new Error('Upload failed');
            }
            const data = await response.json();
            setWizardUpload({
                fileId: data.file_id,
                contactCount: data.contact_count,
                name: file.name,
            });
        } catch (err) {
            console.error(err);
            alert('Could not upload CSV. Please try again.');
            setProspectFile(null);
            setWizardUpload(null);
        } finally {
            setUploadingCsv(false);
        }
    };

    const canContinueStep1 =
        campaignName.trim().length > 0 && !!wizardUpload?.fileId && !uploadingCsv;

    const canGenerate = useMemo(() => {
        const emailOk =
            selectedProducts.length > 0 &&
            selectedProducts.every((p) => (prompts[p.name] || '').trim());
        if (!emailOk || !wizardUpload?.fileId) return false;
        if (!sequenceHasLinkedin) return true;
        return selectedProducts.every((p) => (linkedinPrompts[p.name] || '').trim());
    }, [selectedProducts, prompts, linkedinPrompts, wizardUpload?.fileId, sequenceHasLinkedin]);

    const handleContinue = () => {
        if (step === 1 && !canContinueStep1) return;
        if (step < 4) setStep((s) => s + 1);
    };

    const handleBack = () => {
        if (step > 1) setStep((s) => s - 1);
    };

    const requestClose = () => {
        const committed = promptEditorRef.current?.commitCampaignPrompts?.() ?? null;
        const mergedPrompts =
            committed && typeof committed === 'object' && committed.prompts
                ? committed.prompts
                : prompts;
        const mergedLinkedin =
            committed && typeof committed === 'object' && committed.linkedinPrompts
                ? committed.linkedinPrompts
                : linkedinPrompts;
        const payload = {
            id: initialCampaign?.id,
            name: campaignName.trim() || 'Untitled campaign',
            contacts: wizardUpload?.contactCount ?? estimatedContacts ?? 0,
            prospectFileName: wizardUpload?.name || prospectFile?.name || '',
            fileId: wizardUpload?.fileId || null,
            sequence: sequenceSteps,
            parallelTracks,
            selectedProducts,
            generationComplete: genComplete,
            generationProgressPercent: Math.min(100, Math.round(genProgress || 0)),
            wizardStep: step,
            wizardPrompts: mergedPrompts,
            wizardLinkedinPrompts: mergedLinkedin,
        };
        if (onDraftPersist && (payload.fileId || payload.id)) {
            onDraftPersist(payload);
        }
        onOpenChange(false);
    };

    const handleGenerate = async () => {
        if (!canGenerate) {
            alert('Select products and fill all prompt templates before generating.');
            return;
        }
        promptEditorRef.current?.commitCampaignPrompts?.();
        try {
            const res = await apiFetch('/api/save-prompts', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    file_id: wizardUpload.fileId,
                    prompts,
                    products: selectedProducts.map((p) => p.name),
                    linkedin_prompts: sequenceHasLinkedin ? linkedinPrompts : {},
                    sequence_plan: parallelTracks
                        ? { parallel_tracks: true, steps: sequenceSteps }
                        : sequenceSteps,
                }),
            });
            if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.detail || res.statusText);
            }
        } catch (e) {
            console.error(e);
            alert('Failed to save prompts. Please try again.');
            return;
        }
        setGenRunId((r) => r + 1);
        setGenRunning(true);
    };

    const handleLaunch = () => {
        if (!onComplete) {
            requestClose();
            return;
        }
        onComplete({
            campaignId: initialCampaign?.id ?? null,
            name: campaignName.trim(),
            contacts: wizardUpload?.contactCount || estimatedContacts || 0,
            prospectFileName: wizardUpload?.name || prospectFile?.name || '',
            fileId: wizardUpload?.fileId || null,
            sequence: sequenceSteps,
            parallelTracks,
            selectedProducts,
            generationComplete: genComplete,
            generationProgressPercent: Math.min(100, Math.round(genProgress || 0)),
        });
        onOpenChange(false);
    };

    useEffect(() => {
        if (!open) return;
        const onKey = (e) => {
            if (e.key === 'Escape') requestClose();
        };
        window.addEventListener('keydown', onKey);
        return () => window.removeEventListener('keydown', onKey);
    }, [open, requestClose]);

    if (!open) return null;

    const modal = (
        <div
            className="fixed inset-0 z-[100] flex items-center justify-center p-4 sm:p-6"
            role="dialog"
            aria-modal="true"
            aria-labelledby="create-campaign-title"
        >
            <button
                type="button"
                className="absolute inset-0 bg-slate-900/40 backdrop-blur-[2px]"
                aria-label="Close"
                onClick={() => requestClose()}
            />
            <div
                className={cn(
                    'relative z-[101] flex max-h-[min(92vh,900px)] w-full flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-2xl shadow-violet-200/30',
                    step === 2 || step === 3 ? 'max-w-4xl' : 'max-w-3xl'
                )}
            >
                <div className="flex items-center justify-between border-b border-slate-100 px-5 py-4">
                    <h2 id="create-campaign-title" className="text-lg font-semibold text-slate-900">
                        Create Campaign
                    </h2>
                    <button
                        type="button"
                        onClick={() => requestClose()}
                        className="rounded-lg p-2 text-slate-400 transition hover:bg-slate-100 hover:text-slate-700"
                    >
                        <X className="h-5 w-5" />
                    </button>
                </div>

                <div className="border-b border-slate-100 bg-slate-50/80 px-4 py-4 sm:px-6">
                    <div className="flex flex-wrap items-start justify-between gap-4">
                        {STEPS.map((s) => {
                            const active = step === s.id;
                            const done = step > s.id;
                            return (
                                <div key={s.id} className="flex min-w-[120px] flex-1 flex-col items-center gap-2">
                                    <div
                                        className={cn(
                                            'flex h-10 w-10 items-center justify-center rounded-full text-sm font-semibold transition',
                                            active &&
                                                'bg-violet-600 text-white ring-4 ring-violet-100',
                                            done && !active && 'bg-violet-100 text-violet-800',
                                            !active && !done && 'border-2 border-slate-200 bg-white text-slate-400'
                                        )}
                                    >
                                        {s.id}
                                    </div>
                                    <span
                                        className={cn(
                                            'text-center text-xs font-medium sm:text-sm',
                                            active ? 'text-violet-700' : 'text-slate-500'
                                        )}
                                    >
                                        {s.label}
                                    </span>
                                </div>
                            );
                        })}
                    </div>
                </div>

                <div className="min-h-0 flex-1 overflow-y-auto px-5 py-6 sm:px-8">
                    {step === 1 ? (
                        <div className="space-y-6">
                            <div>
                                <span className="inline-flex rounded-md bg-slate-100 px-2 py-0.5 text-[10px] font-medium uppercase tracking-wide text-slate-500">
                                    Step 1
                                </span>
                            </div>
                            <div>
                                <label className="mb-1.5 block text-sm font-medium text-slate-800">
                                    Campaign Name
                                </label>
                                <Input
                                    placeholder="e.g., Q4 Enterprise Tech Outreach"
                                    value={campaignName}
                                    onChange={(e) => setCampaignName(e.target.value)}
                                    className="max-w-lg"
                                />
                            </div>
                            <div>
                                <label className="mb-1.5 block text-sm font-medium text-slate-800">
                                    Prospect List (Apollo CSV)
                                </label>
                                <div
                                    className={cn(
                                        'relative flex min-h-[200px] cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed px-4 py-8 transition',
                                        dragOver
                                            ? 'border-violet-400 bg-violet-50/50'
                                            : 'border-slate-200 bg-slate-50/50 hover:border-violet-300'
                                    )}
                                    onDragOver={(e) => {
                                        e.preventDefault();
                                        setDragOver(true);
                                    }}
                                    onDragLeave={() => setDragOver(false)}
                                    onDrop={(e) => {
                                        e.preventDefault();
                                        setDragOver(false);
                                        const f = e.dataTransfer.files?.[0];
                                        pickFile(f);
                                    }}
                                    onClick={() => !uploadingCsv && document.getElementById('wizard-csv-input')?.click()}
                                >
                                    <input
                                        id="wizard-csv-input"
                                        type="file"
                                        accept=".csv"
                                        className="hidden"
                                        onChange={(e) => pickFile(e.target.files?.[0])}
                                    />
                                    <div className="flex h-12 w-12 items-center justify-center rounded-full bg-violet-100 text-violet-600">
                                        <Upload className="h-6 w-6" />
                                    </div>
                                    <p className="mt-3 text-center text-sm font-semibold text-slate-800">
                                        Drag and drop your CSV here
                                    </p>
                                    <Button
                                        type="button"
                                        variant="outline"
                                        className="mt-4"
                                        disabled={uploadingCsv}
                                        onClick={(e) => {
                                            e.stopPropagation();
                                            document.getElementById('wizard-csv-input')?.click();
                                        }}
                                    >
                                        Browse Files
                                    </Button>
                                    {uploadingCsv ? (
                                        <p className="mt-3 text-xs font-medium text-violet-700">Uploading…</p>
                                    ) : wizardUpload ? (
                                        <p className="mt-3 text-xs font-medium text-violet-700">
                                            {wizardUpload.name}
                                            {wizardUpload.contactCount
                                                ? ` · ${Number(wizardUpload.contactCount).toLocaleString()} contacts`
                                                : estimatedContacts > 0
                                                  ? ` · ~${estimatedContacts.toLocaleString()} rows`
                                                  : ''}
                                        </p>
                                    ) : prospectFile ? (
                                        <p className="mt-3 text-xs text-amber-700">Upload failed — try another file.</p>
                                    ) : null}
                                </div>
                            </div>
                        </div>
                    ) : step === 2 ? (
                        <CampaignSequenceBuilder
                            value={sequenceSteps}
                            onChange={setSequenceSteps}
                            parallelTracks={parallelTracks}
                            onParallelTracksChange={setParallelTracks}
                            linkedinDefaults={linkedinDefaults}
                            mailboxDefaults={mailboxDefaults}
                        />
                    ) : step === 3 ? (
                        <div className="space-y-8">
                            <ProductSelector
                                selectedProducts={selectedProducts}
                                onProductsChange={setSelectedProducts}
                            />
                            {selectedProducts.length > 0 ? (
                                <>
                                    <PromptEditor
                                        ref={promptEditorRef}
                                        selectedProducts={selectedProducts}
                                        prompts={prompts}
                                        onPromptsChange={setPrompts}
                                        variant="campaign"
                                        includeLinkedinInCampaign={sequenceHasLinkedin}
                                        linkedinPrompts={linkedinPrompts}
                                        onLinkedinPromptsChange={setLinkedinPrompts}
                                    />
                                    <div className="flex flex-wrap items-center gap-3">
                                        <Button
                                            type="button"
                                            disabled={!canGenerate || genRunning}
                                            className="bg-gradient-to-r from-violet-600 to-purple-600 hover:from-violet-700 hover:to-purple-700"
                                            onClick={handleGenerate}
                                        >
                                            <Sparkles className="mr-2 h-4 w-4" />
                                            {genRunning ? 'Generating…' : 'Generate'}
                                        </Button>
                                        {genRunning ? (
                                            <span className="text-sm text-slate-600">
                                                Running in the background — you can go to the next step anytime.
                                            </span>
                                        ) : null}
                                    </div>
                                    <WizardSequencePreview
                                        contacts={genContacts}
                                        sequences={genSequences}
                                        isGenerating={genRunning}
                                        generationComplete={genComplete}
                                        generationStarted={genRunId > 0 || genSequences.length > 0}
                                        progress={genProgress}
                                        contactCount={wizardUpload?.contactCount}
                                        selectedProducts={selectedProducts}
                                        sequenceHasLinkedin={sequenceHasLinkedin}
                                        genPhase={genPhase}
                                    />
                                </>
                            ) : (
                                <p className="text-sm text-slate-500">Select at least one product to edit prompts.</p>
                            )}
                        </div>
                    ) : (
                        <div className="space-y-6">
                            <div className="rounded-xl border border-slate-200 bg-white p-4 shadow-sm">
                                <p className="text-sm font-medium text-slate-800">Sequence</p>
                                <ReviewSequenceTimeline steps={sequenceSteps} parallelTracks={parallelTracks} />
                            </div>
                            <div>
                                <p className="mb-2 text-sm font-medium text-slate-800">Sample preview</p>
                                {genContacts[0] ? (
                                    <SequenceCard contact={genContacts[0]} index={0} />
                                ) : (
                                    <div className="rounded-xl border border-dashed border-slate-200 bg-slate-50/80 px-4 py-10 text-center text-sm text-slate-600">
                                        No generated copy for the first contact yet. You can still launch — content
                                        will keep filling in the background. Return to step 3 or open this campaign from
                                        the dashboard to watch progress.
                                    </div>
                                )}
                            </div>
                            <div className="flex flex-wrap items-center justify-between gap-3 rounded-xl border border-slate-100 bg-slate-50/80 px-4 py-3 text-sm text-slate-700">
                                <div>
                                    <span className="font-semibold text-slate-900">{campaignName || 'Campaign'}</span>
                                    <span className="mx-2 text-slate-300">·</span>
                                    <span>
                                        {(wizardUpload?.contactCount ?? estimatedContacts ?? 0).toLocaleString()}{' '}
                                        prospects
                                    </span>
                                    {(wizardUpload?.name || prospectFile?.name) && (
                                        <>
                                            <span className="mx-2 text-slate-300">·</span>
                                            <span className="text-slate-600">
                                                {wizardUpload?.name || prospectFile?.name}
                                            </span>
                                        </>
                                    )}
                                </div>
                                {genRunning || (genSequences.length > 0 && !genComplete) ? (
                                    <span className="text-xs font-medium text-violet-700">
                                        Content generation {genComplete ? 'complete' : 'in progress'}
                                    </span>
                                ) : null}
                            </div>
                        </div>
                    )}
                </div>

                <div className="flex flex-wrap items-center justify-end gap-2 border-t border-slate-100 bg-white px-5 py-4 sm:px-8">
                    {step === 4 ? (
                        <Button
                            type="button"
                            className="bg-violet-600 text-white hover:bg-violet-700"
                            onClick={handleLaunch}
                        >
                            Launch campaign
                        </Button>
                    ) : null}
                    {step > 1 ? (
                        <Button type="button" variant="outline" onClick={handleBack}>
                            <ArrowLeft className="mr-2 h-4 w-4" />
                            Back
                        </Button>
                    ) : null}
                    {step < 4 ? (
                        <Button
                            type="button"
                            disabled={step === 1 && !canContinueStep1}
                            className="bg-violet-600 text-white hover:bg-violet-700 disabled:opacity-40"
                            onClick={handleContinue}
                        >
                            {step === 1
                                ? 'Continue to Sequence'
                                : step === 3
                                  ? 'Continue to Review & Launch'
                                  : `Continue to ${STEPS[step]?.label ?? 'next'}`}
                            <ArrowRight className="ml-2 h-4 w-4" />
                        </Button>
                    ) : null}
                </div>
            </div>
        </div>
    );

    return typeof document !== 'undefined' ? createPortal(modal, document.body) : null;
}
