import { AdminPageHeader, adminLayout } from '@/Layouts/AdminLayout';
import { Button, Card } from '@/Components/ui';
import { cn } from '@/lib/cn';
import { Head } from '@inertiajs/react';
import {
    AlertCircle,
    CheckCircle2,
    Eye,
    Loader2,
    Trash2,
    Wrench,
} from 'lucide-react';
import { useState } from 'react';

type Task = {
    key: string;
    label: string;
    description: string;
    accepts_days: boolean;
    default_days: number | null;
    /** Per-task label for the numeric knob. Defaults to "Retention (days)"
     *  on the server side; theme-versions overrides to "Keep newest
     *  (versions)" since its scalar is a count, not a day window. */
    knob_label: string;
    eligible: number;
};

type Props = {
    tasks: Task[];
};

type RunResult =
    | {
          kind: 'ok';
          dry_run: boolean;
          days: number | null;
          output: string;
          exit_code: number;
          eligible_after: number;
      }
    | { kind: 'error'; message: string };

function csrfHeaders(): Record<string, string> {
    const cookieMatch = document.cookie.match(/(?:^|;\s*)XSRF-TOKEN=([^;]+)/);
    const xsrf = cookieMatch ? decodeURIComponent(cookieMatch[1]) : null;
    return {
        'Content-Type': 'application/json',
        Accept: 'application/json',
        'X-Requested-With': 'XMLHttpRequest',
        ...(xsrf ? { 'X-XSRF-TOKEN': xsrf } : {}),
    };
}

function AdminMaintenance({ tasks }: Props) {
    return (
        <>
            <Head title="Admin · Maintenance" />
            <AdminPageHeader
                title="Maintenance"
                description="Manual-trigger surface for every scheduled cleanup. Each task has a Preview (dry-run) before Purge so you can see what would be deleted first."
            />
            <Card
                padding="md"
                className="mb-5 flex items-start gap-3 border-accent/30 bg-accent/[0.03]"
            >
                <span className="mt-0.5 flex h-7 w-7 items-center justify-center rounded-md bg-accent/10 text-accent">
                    <Wrench className="h-4 w-4" strokeWidth={2.5} />
                </span>
                <div className="text-[12px] text-muted-foreground">
                    These tasks run automatically via the weekly cron
                    schedule. Triggering them here runs the same artisan
                    command immediately — useful for one-off cleanups (e.g.
                    after a bulk import or pre-launch test sweep) or when
                    the cron hasn't fired yet. Preview is non-destructive.
                </div>
            </Card>

            <div className="space-y-4">
                {tasks.map((task) => (
                    <TaskCard key={task.key} task={task} />
                ))}
            </div>
        </>
    );
}

AdminMaintenance.layout = adminLayout;

export default AdminMaintenance;

function TaskCard({ task }: { task: Task }) {
    const [days, setDays] = useState<string>(
        task.default_days !== null ? String(task.default_days) : '',
    );
    const [eligible, setEligible] = useState(task.eligible);
    const [running, setRunning] = useState<'preview' | 'purge' | null>(null);
    const [confirming, setConfirming] = useState(false);
    const [result, setResult] = useState<RunResult | null>(null);

    const run = async (mode: 'preview' | 'purge'): Promise<void> => {
        setRunning(mode);
        setResult(null);
        try {
            const body: Record<string, unknown> = { task: task.key };
            if (task.accepts_days && days.trim() !== '') {
                body.days = Number.parseInt(days, 10);
            }
            const url =
                mode === 'preview'
                    ? '/admin/maintenance/preview'
                    : '/admin/maintenance/purge';
            const res = await fetch(url, {
                method: 'POST',
                credentials: 'same-origin',
                headers: csrfHeaders(),
                body: JSON.stringify(body),
            });
            const json = (await res.json().catch(() => null)) as {
                ok?: boolean;
                dry_run?: boolean;
                days?: number | null;
                output?: string;
                exit_code?: number;
                eligible_after?: number;
                message?: string;
                errors?: Record<string, string[]>;
            } | null;
            if (!res.ok || json?.ok === false) {
                const validation =
                    json?.errors && typeof json.errors === 'object'
                        ? Object.values(json.errors)
                              .flat()
                              .filter((s): s is string => typeof s === 'string')
                              .join(' ')
                        : null;
                setResult({
                    kind: 'error',
                    message:
                        validation ||
                        json?.message ||
                        `Failed (${res.status}).`,
                });
                return;
            }
            setResult({
                kind: 'ok',
                dry_run: json?.dry_run ?? mode === 'preview',
                days: json?.days ?? null,
                output: json?.output ?? '',
                exit_code: json?.exit_code ?? 0,
                eligible_after: json?.eligible_after ?? 0,
            });
            if (typeof json?.eligible_after === 'number') {
                setEligible(json.eligible_after);
            }
            setConfirming(false);
        } catch {
            setResult({ kind: 'error', message: 'Network error. Try again.' });
        } finally {
            setRunning(null);
        }
    };

    return (
        <Card
            padding="md"
            className="flex flex-col gap-3"
            data-testid={`admin-maintenance-task-${task.key}`}
        >
            <div className="flex flex-wrap items-start justify-between gap-3">
                <div className="min-w-0 flex-1">
                    <h3 className="text-[13px] font-semibold text-foreground">
                        {task.label}
                    </h3>
                    <p className="mt-1 text-[12px] text-muted-foreground">
                        {task.description}
                    </p>
                </div>
                <span
                    className={cn(
                        'shrink-0 rounded-full border px-2.5 py-0.5 text-[11px] font-medium tabular-nums',
                        eligible > 0
                            ? 'border-warning/30 bg-warning/10 text-warning'
                            : 'border-border bg-muted text-muted-foreground',
                    )}
                    title="Rows the cron would delete today with the configured retention"
                >
                    {eligible.toLocaleString()} eligible
                </span>
            </div>

            <div className="flex flex-wrap items-end gap-3 rounded-md border border-border bg-muted/20 p-3">
                {task.accepts_days && (
                    <label className="flex flex-col gap-1">
                        <span className="text-[11px] font-medium text-foreground/80">
                            {task.knob_label}
                        </span>
                        <input
                            type="number"
                            min={0}
                            max={3650}
                            value={days}
                            onChange={(e) => setDays(e.target.value)}
                            placeholder={
                                task.default_days !== null
                                    ? String(task.default_days)
                                    : ''
                            }
                            className="h-8 w-24 rounded-md border border-border bg-card px-2 text-[12px] tabular-nums text-foreground focus:border-accent/50 focus:outline-none focus:ring-1 focus:ring-accent/30"
                            data-testid={`admin-maintenance-days-${task.key}`}
                        />
                    </label>
                )}

                <div className="ml-auto flex flex-wrap gap-2">
                    <Button
                        type="button"
                        variant="secondary"
                        size="sm"
                        onClick={() => run('preview')}
                        disabled={running !== null}
                        data-testid={`admin-maintenance-preview-${task.key}`}
                    >
                        {running === 'preview' ? (
                            <span className="flex items-center gap-1.5">
                                <Loader2 className="h-3 w-3 animate-spin" />
                                Previewing…
                            </span>
                        ) : (
                            <span className="flex items-center gap-1.5">
                                <Eye className="h-3 w-3" strokeWidth={2.5} />
                                Preview
                            </span>
                        )}
                    </Button>
                    {!confirming ? (
                        <Button
                            type="button"
                            variant="primary"
                            size="sm"
                            onClick={() => setConfirming(true)}
                            disabled={running !== null}
                            data-testid={`admin-maintenance-purge-${task.key}`}
                        >
                            <span className="flex items-center gap-1.5">
                                <Trash2 className="h-3 w-3" strokeWidth={2.5} />
                                Purge now
                            </span>
                        </Button>
                    ) : (
                        <>
                            <Button
                                type="button"
                                variant="primary"
                                size="sm"
                                onClick={() => run('purge')}
                                disabled={running !== null}
                                data-testid={`admin-maintenance-purge-confirm-${task.key}`}
                            >
                                {running === 'purge' ? (
                                    <span className="flex items-center gap-1.5">
                                        <Loader2 className="h-3 w-3 animate-spin" />
                                        Purging…
                                    </span>
                                ) : (
                                    'Confirm purge'
                                )}
                            </Button>
                            <Button
                                type="button"
                                variant="secondary"
                                size="sm"
                                onClick={() => setConfirming(false)}
                                disabled={running !== null}
                            >
                                Cancel
                            </Button>
                        </>
                    )}
                </div>
            </div>

            {result && (
                <div
                    className={cn(
                        'rounded-md border px-3 py-2 text-[11.5px]',
                        result.kind === 'ok'
                            ? 'border-success/30 bg-success/[0.03]'
                            : 'border-destructive/30 bg-destructive/5',
                    )}
                    role={result.kind === 'ok' ? 'status' : 'alert'}
                    data-testid={`admin-maintenance-result-${task.key}`}
                >
                    {result.kind === 'ok' ? (
                        <div className="flex items-start gap-2">
                            <CheckCircle2
                                className="mt-0.5 h-3.5 w-3.5 shrink-0 text-success"
                                strokeWidth={2.5}
                            />
                            <div className="min-w-0 flex-1">
                                <p className="font-medium text-foreground">
                                    {result.dry_run
                                        ? 'Preview complete'
                                        : 'Purge complete'}
                                    {result.days !== null
                                        ? ` (retention: ${result.days} days)`
                                        : ''}
                                </p>
                                {result.output && (
                                    <pre className="mt-2 max-h-48 overflow-auto whitespace-pre-wrap rounded bg-muted/40 p-2 font-mono text-[11px] text-foreground/80">
                                        {result.output.trim() || '(no output)'}
                                    </pre>
                                )}
                            </div>
                        </div>
                    ) : (
                        <div className="flex items-start gap-2">
                            <AlertCircle
                                className="mt-0.5 h-3.5 w-3.5 shrink-0 text-destructive"
                                strokeWidth={2.5}
                            />
                            <p className="text-destructive">{result.message}</p>
                        </div>
                    )}
                </div>
            )}
        </Card>
    );
}
