"use client";

import { useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { api, Workflow } from "@/lib/api";
import { Button } from "@/components/ui";

/*
 * Presets write cron underneath rather than being their own storage format:
 * one representation, and the raw field is always the truth. The next three
 * occurrences come from the server so the browser cannot disagree with the
 * scheduler about what an expression means.
 */

const PRESETS: { label: string; cron: string }[] = [
    { label: "Hourly", cron: "0 * * * *" },
    { label: "Nightly, 02:00", cron: "0 2 * * *" },
    { label: "Weekly, Sun 02:00", cron: "0 2 * * 0" },
    { label: "Monthly, 1st 02:00", cron: "0 2 1 * *" },
];

const ZONES = ["UTC", "Europe/London", "Europe/Berlin", "America/New_York", "America/Los_Angeles", "Asia/Singapore", "Australia/Sydney"];

export function ScheduleCard({ workflow }: { workflow: Workflow }) {
    const queryClient = useQueryClient();
    const [enabled, setEnabled] = useState(workflow.schedule?.enabled ?? false);
    const [cron, setCron] = useState(workflow.schedule?.cron ?? "0 2 * * 0");
    const [tz, setTz] = useState(workflow.schedule?.tz ?? Intl.DateTimeFormat().resolvedOptions().timeZone ?? "UTC");
    const [error, setError] = useState<string | null>(null);

    // isError, not !preview: an in-flight query and a rejected expression both
    // leave data undefined, so keying the invalid message off the data alone
    // flashes "not valid" at every keystroke on a perfectly good cron string.
    const { data: preview, isError: previewFailed } = useQuery({
        queryKey: ["schedule-preview", workflow.workflow_id, cron, tz],
        queryFn: () => api.previewSchedule(workflow.workflow_id, cron, tz),
        retry: false,
    });

    const { mutate: save, isPending } = useMutation({
        mutationFn: () => api.setWorkflowSchedule(workflow.workflow_id, { enabled, cron, tz }),
        onSuccess: () => {
            queryClient.invalidateQueries({ queryKey: ["workflows"] });
            setError(null);
        },
        onError: (e: Error) => setError(e.message),
    });

    return (
        // No panel chrome: this renders inside a Modal that already supplies the
        // border, the background and a title bar, and nesting a second card in
        // one produced a box inside a box.
        <div className="border-t border-border-soft pt-4">
            <div className="flex items-baseline justify-between gap-3">
                <h3 className="text-xs font-semibold uppercase tracking-wide text-text-secondary">Schedule</h3>
                <span className="font-mono text-[10px] uppercase tracking-[0.16em] text-text-tertiary">{enabled ? "Active" : "Off"}</span>
            </div>

            <div className="flex flex-col gap-4 pt-4">
                <label className="flex items-start gap-3">
                    <input type="checkbox" checked={enabled} onChange={(e) => setEnabled(e.target.checked)} className="mt-0.5 h-4 w-4 accent-accent" />
                    <span>
                        <span className="block text-sm text-text-primary">Run on a schedule</span>
                        <span className="mt-0.5 block text-xs text-text-tertiary">A scheduled run is skipped, not queued, while a previous run is still going.</span>
                    </span>
                </label>

                <div className="flex flex-wrap gap-2">
                    {PRESETS.map((p) => (
                        <button
                            key={p.cron}
                            type="button"
                            onClick={() => setCron(p.cron)}
                            className={`rounded-lg border px-3 py-1.5 text-xs transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${
                                cron === p.cron ? "border-accent bg-accent/10 text-accent" : "border-border bg-surface-2 text-text-secondary hover:border-accent/40"
                            }`}
                        >
                            {p.label}
                        </button>
                    ))}
                </div>

                <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
                    <label className="block">
                        <span className="mb-1.5 block text-sm font-medium text-text-secondary">Cron expression</span>
                        <input
                            value={cron}
                            onChange={(e) => setCron(e.target.value)}
                            className="w-full rounded-lg border border-border bg-surface-2 px-3 py-2 font-mono text-sm text-text-primary focus:border-accent/50 focus:outline-none focus:ring-1 focus:ring-accent/30"
                        />
                        <span className="mt-1.5 block font-mono text-[11px] text-text-tertiary">minute hour day month weekday</span>
                    </label>

                    <label className="block">
                        <span className="mb-1.5 block text-sm font-medium text-text-secondary">Timezone</span>
                        <select
                            value={tz}
                            onChange={(e) => setTz(e.target.value)}
                            className="w-full rounded-lg border border-border bg-surface-2 px-3 py-2 text-sm text-text-primary focus:border-accent/50 focus:outline-none"
                        >
                            {[...new Set([tz, ...ZONES])].map((z) => (
                                <option key={z} value={z}>
                                    {z}
                                </option>
                            ))}
                        </select>
                    </label>
                </div>

                <div className="rounded-lg bg-well px-4 py-3">
                    <p className="font-mono text-[10px] uppercase tracking-[0.16em] text-text-tertiary">Next three runs</p>
                    {previewFailed ? (
                        <p className="mt-1.5 font-mono text-[11.5px] text-danger">That expression is not valid.</p>
                    ) : preview ? (
                        <ul className="mt-1.5 flex flex-col gap-0.5 font-mono text-[11.5px] text-text-secondary">
                            {preview.occurrences.map((o) => (
                                <li key={o}>{new Date(o).toLocaleString()}</li>
                            ))}
                        </ul>
                    ) : (
                        <p className="mt-1.5 font-mono text-[11.5px] text-text-tertiary">Working it out…</p>
                    )}
                </div>

                {workflow.last_skipped && (
                    <p className="rounded-lg border border-warning/30 bg-warning/10 px-4 py-3 text-xs text-warning">
                        Skipped {new Date(workflow.last_skipped.due).toLocaleString()} —{" "}
                        {workflow.last_skipped.reason === "already_running"
                            ? "previous run still active"
                            : workflow.last_skipped.reason === "missed"
                              ? "the control plane was not running at the time"
                              : workflow.last_skipped.reason}
                    </p>
                )}

                {error && <p className="text-sm text-danger">{error}</p>}

                <div>
                    {/* Gated on the preview: the server has already rejected this
                        expression once, and submitting it only earns the same 400. */}
                    <Button variant="primary" loading={isPending} disabled={previewFailed} onClick={() => save()}>
                        Save schedule
                    </Button>
                </div>
            </div>
        </div>
    );
}
