"use client";

import { useEffect, useState } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import Link from "next/link";
import { api } from "@/lib/api";
import { useAuth } from "@/components/AuthProvider";
import { Button, Card } from "@/components/ui";
import { Field } from "@/components/settings/Field";
import { Group } from "@/components/settings/Group";
import { SectionCard } from "@/components/settings/SectionCard";
import { MembersCard } from "@/components/settings/MembersCard";
import { AuthProvidersCard } from "@/components/settings/AuthProvidersCard";

const numberInputClass =
    "w-32 rounded border border-border bg-surface-2 px-3 py-2 text-sm text-text-primary focus:border-accent/50 focus:outline-none focus:ring-1 focus:ring-accent/30";

function BellIcon() {
    return (
        <svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
            <path
                strokeLinecap="round"
                strokeLinejoin="round"
                d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0"
            />
        </svg>
    );
}

function ServerIcon() {
    return (
        <svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
            <path
                strokeLinecap="round"
                strokeLinejoin="round"
                d="M21.75 17.25v-.228a4.5 4.5 0 00-.12-1.03l-2.268-9.64a3.375 3.375 0 00-3.285-2.602H7.923a3.375 3.375 0 00-3.285 2.602l-2.268 9.64a4.5 4.5 0 00-.12 1.03v.228m19.5 0a3 3 0 01-3 3H5.25a3 3 0 01-3-3m19.5 0a3 3 0 00-3-3H5.25a3 3 0 00-3 3m16.5 0h.008v.008h-.008v-.008zm-3 0h.008v.008h-.008v-.008z"
            />
        </svg>
    );
}

function DocumentIcon() {
    return (
        <svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
            <path
                strokeLinecap="round"
                strokeLinejoin="round"
                d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z"
            />
        </svg>
    );
}

function KeyIcon() {
    return (
        <svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
            <path
                strokeLinecap="round"
                strokeLinejoin="round"
                d="M15.75 5.25a3 3 0 013 3m3 0a6 6 0 01-7.029 5.912c-.563-.097-1.159.026-1.563.43L10.5 17.25H8.25v2.25H6v2.25H2.25v-2.818c0-.597.237-1.17.659-1.591l6.499-6.499c.404-.404.527-1 .43-1.563A6 6 0 1121.75 8.25z"
            />
        </svg>
    );
}

function SecretsTokenCard({ tokenSet, rotatedAt }: { tokenSet: boolean; rotatedAt?: string }) {
    const queryClient = useQueryClient();
    const [token, setToken] = useState<string | null>(null);
    const [copied, setCopied] = useState(false);
    const readUrl = typeof window !== "undefined" ? `${window.location.origin}/api/secrets/<group>/values` : "/api/secrets/<group>/values";

    const { mutate: rotate, isPending } = useMutation({
        mutationFn: api.rotateSecretsToken,
        onSuccess: (res) => {
            setToken(res.token);
            queryClient.invalidateQueries({ queryKey: ["settings"] });
        },
    });

    async function copy() {
        if (!token) return;
        await navigator.clipboard.writeText(token);
        setCopied(true);
        setTimeout(() => setCopied(false), 2000);
    }

    return (
        <SectionCard title="Secrets read token (ESO)" description="Kubernetes External Secrets Operator authenticates to the read endpoint with this bearer token." icon={<KeyIcon />}>
            {/* break-words, not the default: the read URL is one unbreakable
                token, so on a narrow card it overflows rather than wrapping. */}
            <p className="mb-4 break-words text-sm text-text-secondary">
                Point your <span className="font-mono">ClusterSecretStore</span> at <span className="font-mono text-text-primary">{readUrl}</span>.
            </p>

            <div className="mb-4 flex items-center gap-2 text-sm">
                <span className={`inline-block h-2 w-2 rounded-full ${tokenSet ? "bg-success" : "bg-text-tertiary"}`} />
                <span className="text-text-secondary">
                    {tokenSet ? "A read token is configured" : "No read token configured yet"}
                    {tokenSet && rotatedAt && ` · rotated ${new Date(rotatedAt).toLocaleString()}`}
                </span>
            </div>

            {token && (
                <div className="mb-4 rounded border border-warning/30 bg-warning/10 p-3">
                    <p className="mb-2 text-xs font-medium text-warning">Copy this token now it will not be shown again.</p>
                    <div className="flex items-center gap-2">
                        <code className="flex-1 overflow-x-auto rounded bg-well px-2 py-1.5 font-mono text-xs text-text-primary">{token}</code>
                        <Button type="button" variant="ghost" size="sm" onClick={copy}>
                            {copied ? "Copied!" : "Copy"}
                        </Button>
                    </div>
                </div>
            )}

            <Button type="button" variant="primary" loading={isPending} onClick={() => rotate()}>
                {tokenSet ? "Rotate token" : "Generate token"}
            </Button>
            {tokenSet && <p className="mt-2 text-xs text-text-tertiary">Rotating invalidates the previous token. Update the Kubernetes secret afterwards.</p>}
        </SectionCard>
    );
}

export default function SettingsPage() {
    const queryClient = useQueryClient();
    const { instance, isAdmin } = useAuth();

    const { data: settings, isLoading } = useQuery({
        queryKey: ["settings"],
        queryFn: api.getSettings,
        enabled: isAdmin,
    });

    const { data: channels } = useQuery({
        queryKey: ["channels"],
        queryFn: api.listChannels,
        enabled: isAdmin,
    });

    const [thresholdMinutes, setThresholdMinutes] = useState(5);
    const [logRetentionDays, setLogRetentionDays] = useState(30);
    const [offlineChannelIds, setOfflineChannelIds] = useState<string[]>([]);
    const [saved, setSaved] = useState(false);

    useEffect(() => {
        if (!settings) return;
        setThresholdMinutes(settings.alerts.offline_threshold_minutes || 5);
        setLogRetentionDays(settings.workflow_log_retention_days ?? 30);
        setOfflineChannelIds(settings.alerts.offline_channel_ids ?? []);
    }, [settings]);

    // The one place the in-progress form is turned into a payload. Both the
    // Save button and the local-login toggle go through it, so flipping the
    // toggle can never submit a stale copy of the other fields.
    function currentPayload() {
        return {
            alerts: {
                offline_threshold_minutes: thresholdMinutes,
                offline_channel_ids: offlineChannelIds,
            },
            workflow_log_retention_days: logRetentionDays,
        };
    }

    function toggleOfflineChannel(id: string) {
        setOfflineChannelIds((prev) => (prev.includes(id) ? prev.filter((c) => c !== id) : [...prev, id]));
    }

    const { mutate: save, isPending } = useMutation({
        mutationFn: (payload: Parameters<typeof api.saveSettings>[0]) => api.saveSettings(payload),
        onSuccess: () => {
            queryClient.invalidateQueries({ queryKey: ["settings"] });
            setSaved(true);
            setTimeout(() => setSaved(false), 3000);
        },
    });

    function handleSubmit(e: React.FormEvent) {
        e.preventDefault();
        if (!settings) return;

        save(currentPayload());
    }

    if (!isAdmin) {
        return (
            <div className="p-4 sm:p-6 lg:p-8">
                <Card className="max-w-lg">
                    <h1 className="text-base font-bold text-text-primary">You don&apos;t have access</h1>
                    <p className="mt-1 text-sm text-text-secondary">Settings are available to owners and admins only. Ask an administrator if you need access.</p>
                </Card>
            </div>
        );
    }

    if (isLoading) {
        return (
            <div className="flex h-full items-center justify-center">
                <div className="h-8 w-8 animate-spin rounded-full border-2 border-border border-t-accent" />
            </div>
        );
    }

    return (
        <div className="p-4 sm:p-6 lg:p-8">
            <div className="mb-8">
                <h1 className="text-2xl font-extrabold tracking-[-0.03em] text-text-primary">Settings</h1>
                <p className="mt-1 text-sm text-text-secondary">
                    {instance ? `Members, sign-in and monitoring for ${instance.name}.` : "Members, sign-in and monitoring for this instance."}
                </p>
            </div>

            <div className="space-y-10">
                <Group label="Access">
                    <MembersCard />
                    <AuthProvidersCard
                        localLoginEnabled={settings?.local_login_enabled ?? true}
                        onLocalLoginChange={(v) => {
                            if (!settings) return;
                            // Same in-progress form state the main Save button submits
                            // (handleSubmit below), not the stale loaded `settings`
                            // object — otherwise an unsaved edit to the offline
                            // threshold or retention days is silently reverted the
                            // moment this toggle is flipped.
                            save({ ...currentPayload(), local_login_enabled: v });
                        }}
                    />
                </Group>

                <Group label="Monitoring">
                    <SectionCard title="Alerting" description="Alerts are delivered through notification channels, triggered by service monitors and by servers going offline." icon={<BellIcon />}>
                        <div className="flex flex-wrap gap-3">
                            <Link href="/settings/notifications">
                                <Button variant="secondary">Manage notification channels</Button>
                            </Link>
                            <Link href="/monitors">
                                <Button variant="ghost">View monitors</Button>
                            </Link>
                        </div>
                        <p className="mt-4 text-xs text-text-tertiary">
                            Webhook, email (SMTP), Discord, Slack, and Telegram destinations are configured under Notification Channels and attached per monitor.
                        </p>
                    </SectionCard>

                    <form onSubmit={handleSubmit}>
                        <div className="grid grid-cols-1 gap-6 lg:grid-cols-2">
                            <SectionCard title="Server health" description="When to consider an agent-backed server offline, and where to say so." icon={<ServerIcon />}>
                                <Field label="Offline threshold (minutes)" hint="How long a server must be silent before being marked offline. Agents poll every 30s, so 5 minutes is a safe minimum.">
                                    <input type="number" min={1} max={60} value={thresholdMinutes} onChange={(e) => setThresholdMinutes(Number(e.target.value))} className={numberInputClass} />
                                </Field>

                                <div className="mt-6">
                                    <Field label="Offline alert channels" hint="Notification channels an agent-offline alert is sent to. None selected means the event is still audited, but nobody is notified.">
                                        {channels && channels.length > 0 ? (
                                            <div className="space-y-2">
                                                {channels.map((ch) => (
                                                    <label key={ch.channel_id} className="flex items-center gap-2 text-sm text-text-secondary">
                                                        <input
                                                            type="checkbox"
                                                            checked={offlineChannelIds.includes(ch.channel_id)}
                                                            onChange={() => toggleOfflineChannel(ch.channel_id)}
                                                            className="h-4 w-4 rounded border-border bg-surface-2 accent-accent"
                                                        />
                                                        <span className="text-text-primary">{ch.name}</span>
                                                        <span className="text-xs text-text-tertiary">{ch.type}</span>
                                                        {!ch.enabled && <span className="text-xs text-warning">disabled</span>}
                                                    </label>
                                                ))}
                                            </div>
                                        ) : (
                                            <p className="text-sm text-text-tertiary">
                                                No notification channels yet.{" "}
                                                <Link href="/settings/notifications" className="text-accent hover:underline">
                                                    Create one
                                                </Link>
                                                .
                                            </p>
                                        )}
                                    </Field>
                                </div>
                            </SectionCard>

                            <SectionCard title="Workflow logs" description="How long run logs are kept before automatic deletion." icon={<DocumentIcon />}>
                                <Field label="Log retention (days)" hint="0 = keep forever. Applies to per-run step output logs.">
                                    <input type="number" min={0} value={logRetentionDays} onChange={(e) => setLogRetentionDays(Number(e.target.value))} className={numberInputClass} />
                                </Field>
                            </SectionCard>
                        </div>

                        <div className="mt-6 flex items-center gap-3">
                            <Button type="submit" variant="primary" loading={isPending}>
                                {saved ? "Saved!" : "Save settings"}
                            </Button>
                            {saved && <span className="text-sm text-success">Settings saved successfully.</span>}
                        </div>
                    </form>
                </Group>

                <Group label="Integrations">
                    <SecretsTokenCard tokenSet={settings?.secrets?.read_token_set ?? false} rotatedAt={settings?.secrets?.rotated_at} />
                </Group>
            </div>
        </div>
    );
}
