"use client";

import { useEffect, useMemo, useState } from "react";
import api from "../../../lib/api";

type ProviderName = "local" | "ldap" | "oidc" | "saml";

type ProviderStatus = {
    name: ProviderName;
    enabled: boolean;
    configured: boolean;
    user_count: number;
};

type StatusResponse = {
    providers: ProviderStatus[];
    lookup_order: string[];
    jit_provisioning: boolean;
    default_role: string;
    crypto_key_set: boolean;
};

type Rule = { pattern: string; role: "admin" | "editor" | "readonly" };
type MappingsResponse = { mappings: Record<string, Rule[]> };

const PROVIDER_LABELS: Record<ProviderName, string> = {
    local: "Local accounts",
    ldap: "LDAP / Active Directory",
    oidc: "OIDC (Entra ID / Okta / Keycloak)",
    saml: "SAML 2.0",
};

const ROLE_PRESETS = ["admin", "editor", "readonly"] as const;

export default function AuthAdminPage() {
    const [status, setStatus] = useState<StatusResponse | null>(null);
    const [mappings, setMappings] = useState<Record<string, Rule[]>>({});
    const [saving, setSaving] = useState(false);
    const [saveMsg, setSaveMsg] = useState<string>("");
    const [testResults, setTestResults] = useState<Record<string, any>>({});
    const [testing, setTesting] = useState<string>("");
    const [ldapSampleUser, setLdapSampleUser] = useState("");

    const load = async () => {
        const [s, m] = await Promise.all([
            api.get("/api/v1/auth-config/status"),
            api.get("/api/v1/auth-config/role-mappings"),
        ]);
        setStatus(s.data);
        // Ensure every external provider has at least an empty rules list
        const incoming = m.data?.mappings || {};
        const normalised: Record<string, Rule[]> = {};
        for (const p of ["ldap", "oidc", "saml"]) {
            normalised[p] = Array.isArray(incoming[p]) ? incoming[p] : [];
        }
        setMappings(normalised);
    };

    useEffect(() => {
        load().catch(() => {
            /* permission likely; render fallback */
        });
    }, []);

    const addRule = (provider: string) => {
        setMappings((prev) => ({
            ...prev,
            [provider]: [...(prev[provider] || []), { pattern: "", role: "readonly" }],
        }));
    };

    const removeRule = (provider: string, idx: number) => {
        setMappings((prev) => ({
            ...prev,
            [provider]: (prev[provider] || []).filter((_, i) => i !== idx),
        }));
    };

    const updateRule = (provider: string, idx: number, patch: Partial<Rule>) => {
        setMappings((prev) => ({
            ...prev,
            [provider]: (prev[provider] || []).map((r, i) =>
                i === idx ? { ...r, ...patch } : r
            ),
        }));
    };

    const moveRule = (provider: string, idx: number, dir: -1 | 1) => {
        setMappings((prev) => {
            const list = [...(prev[provider] || [])];
            const target = idx + dir;
            if (target < 0 || target >= list.length) return prev;
            [list[idx], list[target]] = [list[target], list[idx]];
            return { ...prev, [provider]: list };
        });
    };

    const saveMappings = async () => {
        setSaving(true);
        setSaveMsg("");
        try {
            // Strip empty patterns before saving
            const cleaned: Record<string, Rule[]> = {};
            for (const [p, rules] of Object.entries(mappings)) {
                cleaned[p] = rules.filter((r) => r.pattern.trim().length > 0);
            }
            await api.put("/api/v1/auth-config/role-mappings", { mappings: cleaned });
            setSaveMsg("Mappings saved.");
            setTimeout(() => setSaveMsg(""), 4000);
        } catch (e: any) {
            setSaveMsg(`Save failed: ${e?.response?.data?.detail || e?.message || "unknown"}`);
        } finally {
            setSaving(false);
        }
    };

    const runTest = async (provider: "ldap" | "oidc" | "saml") => {
        setTesting(provider);
        try {
            const body =
                provider === "ldap"
                    ? { sample_username: ldapSampleUser || null }
                    : {};
            const res = await api.post(`/api/v1/auth-config/${provider}/test`, body);
            setTestResults((prev) => ({ ...prev, [provider]: res.data }));
        } catch (e: any) {
            setTestResults((prev) => ({
                ...prev,
                [provider]: { ok: false, error: e?.response?.data?.detail || e?.message },
            }));
        } finally {
            setTesting("");
        }
    };

    const providers = status?.providers || [];

    return (
        <div className="w-full max-w-5xl mx-auto p-4 space-y-6">
            <header>
                <h1 className="text-2xl font-bold text-gray-900 font-mono">Authentication Providers</h1>
                <p className="text-sm text-gray-500 mt-1">
                    Read-only provider configuration is loaded from environment variables (restart required to apply).
                    Role mappings below are editable at runtime.
                </p>
            </header>

            {/* Global settings */}
            {status && (
                <section className="bg-white border border-gray-200 rounded-md p-4 shadow-sm">
                    <h2 className="text-sm font-bold text-gray-700 font-mono uppercase tracking-wider mb-3">Global</h2>
                    <div className="grid grid-cols-2 gap-3 text-sm font-mono">
                        <div><span className="text-gray-500">Lookup order:</span> <span className="font-bold">{status.lookup_order.join(" → ")}</span></div>
                        <div><span className="text-gray-500">JIT provisioning:</span> <span className="font-bold">{status.jit_provisioning ? "ON" : "OFF"}</span></div>
                        <div><span className="text-gray-500">Default JIT role:</span> <span className="font-bold">{status.default_role}</span></div>
                        <div>
                            <span className="text-gray-500">Crypto key (Fernet):</span>{" "}
                            <span className={`font-bold ${status.crypto_key_set ? "text-green-600" : "text-red-600"}`}>
                                {status.crypto_key_set ? "set" : "MISSING — set AUTH_PROVIDER_CRYPTO_KEY"}
                            </span>
                        </div>
                    </div>
                </section>
            )}

            {/* Provider status cards */}
            <section className="grid grid-cols-1 md:grid-cols-2 gap-3">
                {providers.map((p) => (
                    <div key={p.name} className="bg-white border border-gray-200 rounded-md p-4 shadow-sm">
                        <div className="flex items-center justify-between">
                            <h3 className="text-sm font-bold font-mono">{PROVIDER_LABELS[p.name]}</h3>
                            <div className="flex gap-1">
                                <span className={`text-[10px] px-2 py-0.5 rounded font-mono font-bold uppercase ${p.enabled ? "bg-green-100 text-green-700" : "bg-gray-100 text-gray-500"}`}>
                                    {p.enabled ? "Enabled" : "Disabled"}
                                </span>
                                <span className={`text-[10px] px-2 py-0.5 rounded font-mono font-bold uppercase ${p.configured ? "bg-blue-100 text-blue-700" : "bg-orange-100 text-orange-700"}`}>
                                    {p.configured ? "Configured" : "Incomplete"}
                                </span>
                            </div>
                        </div>
                        <div className="mt-2 text-xs text-gray-500 font-mono">{p.user_count} user(s) linked</div>

                        {/* Test button (skip local) */}
                        {p.name !== "local" && (
                            <div className="mt-3 space-y-2">
                                {p.name === "ldap" && (
                                    <input
                                        type="text"
                                        value={ldapSampleUser}
                                        onChange={(e) => setLdapSampleUser(e.target.value)}
                                        placeholder="Optional: sample username to search"
                                        className="w-full text-xs font-mono border border-gray-300 rounded px-2 py-1"
                                    />
                                )}
                                <button
                                    onClick={() => runTest(p.name as any)}
                                    disabled={!p.configured || testing === p.name}
                                    className="w-full text-xs font-mono bg-vulncheck-blue text-white rounded px-2 py-1 hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed"
                                >
                                    {testing === p.name ? "Testing…" : `Test ${p.name.toUpperCase()} connection`}
                                </button>
                                {testResults[p.name] && (
                                    <pre className="text-[10px] bg-gray-50 border border-gray-200 rounded p-2 max-h-60 overflow-auto whitespace-pre-wrap break-all">
                                        {JSON.stringify(testResults[p.name], null, 2)}
                                    </pre>
                                )}
                            </div>
                        )}
                    </div>
                ))}
            </section>

            {/* Role mappings editor */}
            <section className="bg-white border border-gray-200 rounded-md p-4 shadow-sm">
                <div className="flex items-center justify-between mb-3">
                    <div>
                        <h2 className="text-sm font-bold text-gray-700 font-mono uppercase tracking-wider">Group → Role mapping</h2>
                        <p className="text-xs text-gray-500 mt-1">
                            Patterns use fnmatch-style wildcards (<code>*</code>, <code>?</code>) and are matched case-insensitively
                            against each raw group from the IdP. First matching rule wins.
                        </p>
                    </div>
                    <button
                        onClick={saveMappings}
                        disabled={saving}
                        className="text-sm font-mono bg-vulncheck-blue text-white rounded px-4 py-2 hover:bg-blue-600 disabled:opacity-60"
                    >
                        {saving ? "Saving…" : "Save mappings"}
                    </button>
                </div>
                {saveMsg && (
                    <div className="mb-3 text-xs font-mono bg-gray-50 border border-gray-200 rounded p-2">
                        {saveMsg}
                    </div>
                )}

                {(["ldap", "oidc", "saml"] as const).map((provider) => (
                    <div key={provider} className="mb-6">
                        <h3 className="text-xs font-bold font-mono uppercase tracking-wider text-gray-600 mb-2">
                            {PROVIDER_LABELS[provider]}
                        </h3>
                        <div className="border border-gray-200 rounded">
                            <table className="min-w-full text-sm font-mono">
                                <thead className="bg-gray-50">
                                    <tr>
                                        <th className="px-3 py-2 text-left text-[11px] uppercase tracking-wider text-gray-500 w-12">#</th>
                                        <th className="px-3 py-2 text-left text-[11px] uppercase tracking-wider text-gray-500">Group pattern</th>
                                        <th className="px-3 py-2 text-left text-[11px] uppercase tracking-wider text-gray-500 w-32">→ Role</th>
                                        <th className="px-3 py-2 w-32"></th>
                                    </tr>
                                </thead>
                                <tbody>
                                    {(mappings[provider] || []).map((rule, idx) => (
                                        <tr key={idx} className="border-t border-gray-100">
                                            <td className="px-3 py-2 text-xs text-gray-400">{idx + 1}</td>
                                            <td className="px-3 py-2">
                                                <input
                                                    type="text"
                                                    value={rule.pattern}
                                                    onChange={(e) => updateRule(provider, idx, { pattern: e.target.value })}
                                                    placeholder={
                                                        provider === "ldap"
                                                            ? "CN=VulnCheck-Admins,*"
                                                            : provider === "oidc"
                                                                ? "vulncheck-admins  |  <azure-group-uuid>"
                                                                : "VulnCheck-Admins"
                                                    }
                                                    className="w-full text-xs border border-gray-300 rounded px-2 py-1"
                                                />
                                            </td>
                                            <td className="px-3 py-2">
                                                <select
                                                    value={rule.role}
                                                    onChange={(e) => updateRule(provider, idx, { role: e.target.value as any })}
                                                    className="w-full text-xs border border-gray-300 rounded px-2 py-1"
                                                >
                                                    {ROLE_PRESETS.map((r) => (
                                                        <option key={r} value={r}>{r}</option>
                                                    ))}
                                                </select>
                                            </td>
                                            <td className="px-3 py-2 text-right whitespace-nowrap">
                                                <button onClick={() => moveRule(provider, idx, -1)} disabled={idx === 0}
                                                    className="px-1 text-gray-400 hover:text-vulncheck-blue disabled:opacity-30">↑</button>
                                                <button onClick={() => moveRule(provider, idx, +1)} disabled={idx === (mappings[provider]?.length || 0) - 1}
                                                    className="px-1 text-gray-400 hover:text-vulncheck-blue disabled:opacity-30">↓</button>
                                                <button onClick={() => removeRule(provider, idx)}
                                                    className="ml-2 px-2 py-0.5 text-[10px] bg-red-50 text-red-600 border border-red-200 rounded hover:bg-red-100">remove</button>
                                            </td>
                                        </tr>
                                    ))}
                                    {(mappings[provider] || []).length === 0 && (
                                        <tr>
                                            <td colSpan={4} className="px-3 py-3 text-center text-xs text-gray-400 italic">
                                                No rules — users from {provider.toUpperCase()} get the default JIT role ({status?.default_role}).
                                            </td>
                                        </tr>
                                    )}
                                </tbody>
                            </table>
                            <div className="border-t border-gray-100 p-2 bg-gray-50">
                                <button onClick={() => addRule(provider)}
                                    className="text-xs font-mono px-3 py-1 bg-white border border-gray-300 rounded hover:bg-gray-100">
                                    + Add rule
                                </button>
                            </div>
                        </div>
                    </div>
                ))}
            </section>
        </div>
    );
}
