'use client';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useRef, useState } from 'react';
import { Plus, Pencil, Trash2, Upload, Download, Sparkles, ArrowRight, GitBranch, Check, X, Link2, } from 'lucide-react';
import { toast } from 'sonner';
import { fetchRedirectOverview, fetchRedirectRules, fetchRedirectChains, fetchRedirectSuggestions, deleteRedirectRule, flattenRedirectChain, generate404RecoverySuggestions, acceptRedirectSuggestion, dismissRedirectSuggestion, exportRedirectsCsv, importRedirectsCsv, } from '../../lib/seo-service.js';
import { SectionCard, SeoLoading, SeoEmptyState, SeoErrorState, SeoStatusBadge, btnPrimary, btnSecondary, btnGhostIcon, } from '../../components/seo/primitives.js';
import { RedirectEditorDrawer } from '../../components/seo/RedirectEditorDrawer.js';
import { ConfirmDialog } from '../../components/ui/ConfirmDialog.js';
import { useSeoResource } from './useSeoResource.js';
function OverviewCards({ onRefetchKey }) {
    const { data, loading, error, refetch } = useSeoResource(fetchRedirectOverview, [onRefetchKey]);
    if (loading)
        return _jsx(SeoLoading, { label: "Loading redirect overview\u2026" });
    if (error)
        return _jsx(SeoErrorState, { message: error, onRetry: refetch });
    if (!data)
        return null;
    const cards = [
        { label: 'Active redirects', value: data.activeRedirects },
        { label: 'Stale redirects', value: data.staleRedirects },
        { label: '404s tracked', value: data.notFoundCount },
        { label: 'Chains & loops', value: data.chainsAndLoops },
    ];
    return (_jsx("div", { className: "grid grid-cols-2 gap-4 lg:grid-cols-4", children: cards.map((c) => (_jsxs("div", { className: "border-border bg-card rounded-lg border p-4", children: [_jsx("p", { className: "text-muted-foreground text-sm", children: c.label }), _jsx("p", { className: "text-foreground mt-1 text-2xl font-medium tabular-nums", children: c.value })] }, c.label))) }));
}
function Ai404RecoveryCard({ onApplied }) {
    const { data, loading, error, refetch } = useSeoResource(fetchRedirectSuggestions, []);
    const [generating, setGenerating] = useState(false);
    async function handleGenerate() {
        setGenerating(true);
        const res = await generate404RecoverySuggestions();
        setGenerating(false);
        if (res.error) {
            toast.error(res.error);
            return;
        }
        toast.success('Generated 404 recovery suggestions.');
        refetch();
    }
    async function handleAccept(id) {
        const res = await acceptRedirectSuggestion(id);
        if (res.error)
            return toast.error(res.error);
        toast.success('Redirect created from suggestion.');
        refetch();
        onApplied();
    }
    async function handleDismiss(id) {
        const res = await dismissRedirectSuggestion(id);
        if (res.error)
            return toast.error(res.error);
        refetch();
    }
    return (_jsx(SectionCard, { title: "AI 404 Recovery", description: "Suggested redirects for paths returning 404s", action: _jsxs("button", { className: btnSecondary, onClick: handleGenerate, disabled: generating, children: [_jsx(Sparkles, { className: `h-4 w-4 ${generating ? 'animate-pulse' : ''}`, "aria-hidden": true }), generating ? 'Analyzing…' : 'Generate suggestions'] }), children: loading ? (_jsx(SeoLoading, {})) : error ? (_jsx(SeoErrorState, { message: error, onRetry: refetch })) : (data ?? []).length === 0 ? (_jsx(SeoEmptyState, { icon: _jsx(Sparkles, { size: 24 }), title: "No suggestions", description: "Generate suggestions to recover traffic from broken URLs." })) : (_jsx("ul", { className: "divide-border divide-y", children: data.map((s) => (_jsxs("li", { className: "flex items-center justify-between gap-3 py-3 first:pt-0", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("p", { className: "text-foreground flex items-center gap-2 text-sm", children: [_jsx("span", { className: "truncate font-medium", children: s.fromPath }), _jsx(ArrowRight, { className: "text-muted-foreground h-3.5 w-3.5 shrink-0", "aria-hidden": true }), _jsx("span", { className: "text-muted-foreground truncate", children: s.toPath })] }), s.reason && _jsx("p", { className: "text-muted-foreground mt-0.5 text-sm", children: s.reason })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsx(SeoStatusBadge, { label: `${Math.round(s.confidence * 100)}%`, tone: s.confidence >= 0.7 ? 'good' : s.confidence >= 0.4 ? 'fair' : 'poor' }), _jsx("button", { onClick: () => handleAccept(s.id), className: "text-success hover:bg-accent focus-visible:ring-ring rounded-md p-1.5 focus-visible:ring-2 focus-visible:outline-none", "aria-label": `Accept redirect from ${s.fromPath}`, children: _jsx(Check, { className: "h-4 w-4", "aria-hidden": true }) }), _jsx("button", { onClick: () => handleDismiss(s.id), className: "text-muted-foreground hover:bg-accent focus-visible:ring-ring rounded-md p-1.5 focus-visible:ring-2 focus-visible:outline-none", "aria-label": `Dismiss suggestion for ${s.fromPath}`, children: _jsx(X, { className: "h-4 w-4", "aria-hidden": true }) })] })] }, s.id))) })) }));
}
function ChainMapCard({ onFlattened }) {
    const { data, loading, error, refetch } = useSeoResource(fetchRedirectChains, []);
    async function handleFlatten(id) {
        const res = await flattenRedirectChain(id);
        if (res.error)
            return toast.error(res.error);
        toast.success('Chain flattened.');
        refetch();
        onFlattened();
    }
    if (loading)
        return null;
    if (error)
        return null;
    if (!data || data.length === 0)
        return null;
    return (_jsx(SectionCard, { title: "Redirect Chains & Loops", description: "Multi-hop redirects slow crawlers and lose link equity", children: _jsx("ul", { className: "space-y-3", children: data.map((chain) => (_jsxs("li", { className: "border-border flex items-center justify-between gap-3 rounded-md border p-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx(GitBranch, { className: "text-muted-foreground h-4 w-4", "aria-hidden": true }), _jsx(SeoStatusBadge, { label: chain.kind === 'loop' ? 'Loop' : 'Chain', tone: chain.kind === 'loop' ? 'critical' : 'fair' })] }), _jsx("p", { className: "text-foreground flex flex-wrap items-center gap-1 text-sm", children: chain.hops.map((hop, i) => (_jsxs("span", { className: "flex items-center gap-1", children: [_jsx("span", { className: "truncate", children: hop }), i < chain.hops.length - 1 && (_jsx(ArrowRight, { className: "text-muted-foreground h-3 w-3", "aria-hidden": true }))] }, i))) })] }), chain.kind === 'chain' && (_jsx("button", { className: btnSecondary, onClick: () => handleFlatten(chain.id), children: "Flatten" }))] }, chain.id))) }) }));
}
export function RedirectsTab() {
    const [refetchKey, setRefetchKey] = useState(0);
    const { data, loading, error, refetch } = useSeoResource(fetchRedirectRules, [refetchKey]);
    const [editor, setEditor] = useState(null);
    const [confirmDelete, setConfirmDelete] = useState(null);
    const fileRef = useRef(null);
    const bump = () => setRefetchKey((k) => k + 1);
    const refetchAll = () => {
        refetch();
        bump();
    };
    async function handleDelete(rule) {
        const res = await deleteRedirectRule(rule.id);
        if (res.error)
            return toast.error(res.error);
        toast.success('Redirect deleted.');
        refetchAll();
    }
    async function handleExport() {
        const res = await exportRedirectsCsv();
        if (res.error || !res.csv)
            return toast.error(res.error ?? 'Export failed.');
        const blob = new Blob([res.csv], { type: 'text/csv' });
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = 'redirects.csv';
        // Firefox requires the anchor to be in the document for programmatic clicks.
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        // Defer revocation so the browser has a chance to start the download —
        // revoking synchronously can cancel it before it begins.
        setTimeout(() => URL.revokeObjectURL(url), 0);
    }
    async function handleImportFile(file) {
        const csv = await file.text();
        const res = await importRedirectsCsv(csv);
        if (res.error)
            return toast.error(res.error);
        if (res.errors && res.errors.length > 0) {
            toast.error(`Imported ${res.imported ?? 0}, ${res.errors.length} row(s) skipped.`);
        }
        else {
            toast.success(`Imported ${res.imported ?? 0} redirect(s).`);
        }
        refetchAll();
    }
    return (_jsxs("div", { className: "space-y-4", children: [_jsx(OverviewCards, { onRefetchKey: refetchKey }), _jsxs("div", { className: "grid grid-cols-1 gap-4 xl:grid-cols-2", children: [_jsx(Ai404RecoveryCard, { onApplied: refetchAll }), _jsx(ChainMapCard, { onFlattened: refetchAll })] }), _jsx(SectionCard, { title: "Redirect Rules", action: _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx("input", { ref: fileRef, type: "file", accept: ".csv,text/csv", className: "sr-only", "aria-hidden": true, tabIndex: -1, onChange: (e) => {
                                const f = e.target.files?.[0];
                                if (f)
                                    handleImportFile(f);
                                e.target.value = '';
                            } }), _jsxs("button", { className: btnSecondary, onClick: () => fileRef.current?.click(), children: [_jsx(Upload, { className: "h-4 w-4", "aria-hidden": true }), " Import"] }), _jsxs("button", { className: btnSecondary, onClick: handleExport, children: [_jsx(Download, { className: "h-4 w-4", "aria-hidden": true }), " Export"] }), _jsxs("button", { className: btnPrimary, onClick: () => setEditor({ rule: null }), children: [_jsx(Plus, { className: "h-4 w-4", "aria-hidden": true }), " New redirect"] })] }), children: loading ? (_jsx(SeoLoading, { label: "Loading redirects\u2026" })) : error ? (_jsx(SeoErrorState, { message: error, onRetry: refetch })) : (data ?? []).length === 0 ? (_jsx(SeoEmptyState, { icon: _jsx(Link2, { size: 24 }), title: "No redirects yet", description: "Create a redirect or import a CSV to get started.", action: _jsxs("button", { className: btnPrimary, onClick: () => setEditor({ rule: null }), children: [_jsx(Plus, { className: "h-4 w-4", "aria-hidden": true }), " New redirect"] }) })) : (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm", "aria-label": "Redirect rules", children: [_jsx("thead", { children: _jsxs("tr", { className: "text-muted-foreground border-border border-b text-left", children: [_jsx("th", { className: "py-2 pr-4 font-medium", children: "Source" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Destination" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Type" }), _jsx("th", { className: "py-2 pr-4 text-right font-medium", children: "Hits" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Status" }), _jsx("th", { className: "py-2 text-right font-medium", children: _jsx("span", { className: "sr-only", children: "Actions" }) })] }) }), _jsx("tbody", { className: "divide-border divide-y", children: data.map((r) => (_jsxs("tr", { className: "hover:bg-accent/40", children: [_jsx("td", { className: "text-foreground py-2.5 pr-4 font-mono", children: r.fromPath }), _jsx("td", { className: "text-muted-foreground py-2.5 pr-4 font-mono", children: r.type === 410 ? _jsx("span", { className: "italic", children: "\u2014 (gone)" }) : r.toPath }), _jsx("td", { className: "text-foreground py-2.5 pr-4 tabular-nums", children: r.type }), _jsx("td", { className: "text-foreground py-2.5 pr-4 text-right tabular-nums", children: r.hits }), _jsx("td", { className: "py-2.5 pr-4", children: _jsxs("span", { className: "flex flex-wrap gap-1.5", children: [_jsx(SeoStatusBadge, { label: r.enabled ? 'Enabled' : 'Disabled', tone: r.enabled ? 'good' : 'neutral' }), r.stale && _jsx(SeoStatusBadge, { label: "Stale", tone: "fair" })] }) }), _jsx("td", { className: "py-2.5 text-right", children: _jsxs("div", { className: "flex justify-end gap-1", children: [_jsx("button", { className: btnGhostIcon, onClick: () => setEditor({ rule: r }), "aria-label": `Edit redirect ${r.fromPath}`, children: _jsx(Pencil, { className: "h-4 w-4", "aria-hidden": true }) }), _jsx("button", { className: btnGhostIcon, onClick: () => setConfirmDelete(r), "aria-label": `Delete redirect ${r.fromPath}`, children: _jsx(Trash2, { className: "h-4 w-4", "aria-hidden": true }) })] }) })] }, r.id))) })] }) })) }), _jsx(RedirectEditorDrawer, { open: editor !== null, onOpenChange: (o) => !o && setEditor(null), rule: editor?.rule ?? null, onSaved: refetchAll }), _jsx(ConfirmDialog, { open: confirmDelete !== null, onClose: () => setConfirmDelete(null), onConfirm: () => confirmDelete && handleDelete(confirmDelete), title: "Delete redirect", description: `Delete the redirect from "${confirmDelete?.fromPath}"? This cannot be undone.`, confirmLabel: "Delete", destructive: true })] }));
}
//# sourceMappingURL=RedirectsTab.js.map