import { useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useParams } from 'react-router-dom';
import { api } from '@/api/client';
import type { CreatedApiKey } from '@/api/types';
import { humanMessage } from '@/auth/AuthProvider';
import { ProjectNav } from '@/components/ProjectNav';
import { RequiresAdmin } from '@/components/RequiresAdmin';

/**
 * Clés API et prise en main.
 *
 * Deux idées gouvernent cet écran :
 *
 *  1. **Le secret n'apparaît qu'une fois**, immédiatement après la création, dans
 *     un encart qu'on ne peut pas manquer. Il n'est pas stocké en clair : le
 *     réafficher est techniquement impossible, et le dire franchement évite de
 *     laisser croire qu'on pourra le retrouver plus tard.
 *
 *  2. **Le mode d'emploi est SOUS la clé**, pas dans une documentation à part.
 *     Le moment où quelqu'un crée une clé est exactement celui où il cherche
 *     quoi en faire.
 */
export function IntegrationPage() {
    const { projectUuid = '' } = useParams();
    const queryClient = useQueryClient();
    const [created, setCreated] = useState<CreatedApiKey | null>(null);

    const stats = useQuery({ queryKey: ['stats', projectUuid], queryFn: () => api.stats(projectUuid) });
    const data = useQuery({ queryKey: ['api-keys', projectUuid], queryFn: () => api.apiKeys(projectUuid) });

    const revoke = useMutation({
        mutationFn: (uuid: string) => api.revokeApiKey(projectUuid, uuid),
        onSuccess: () => void queryClient.invalidateQueries({ queryKey: ['api-keys', projectUuid] }),
    });

    // Le serveur refuse déjà ; ici on refuse LISIBLEMENT.
    if (stats.isSuccess && !stats.data.viewer.canAdminister) {
        return <RequiresAdmin projectUuid={projectUuid} />;
    }

    return (
        <div className="flex h-full flex-col bg-ink-100">
            <header className="shrink-0 border-b border-ink-200 bg-white px-4 py-2.5">
                <ProjectNav projectUuid={projectUuid} canAdminister={stats.data?.viewer.canAdminister ?? false} />
            </header>

            <div className="min-h-0 flex-1 overflow-y-auto">
                <div className="mx-auto max-w-4xl px-6 py-8">
                    <h1 className="text-xl font-semibold tracking-tight text-ink-900">Intégration</h1>
                    <p className="mt-1 text-sm text-ink-500">
                        Clés d'accès et prise en main du CLI.
                    </p>

                    {created !== null && <SecretBanner created={created} onDismiss={() => setCreated(null)} />}

                    <CreateKeyForm
                        projectUuid={projectUuid}
                        environments={(data.data?.environments ?? []).map((e) => e.slug)}
                        scopes={(data.data?.scopes ?? []).map((s) => s.value)}
                        onCreated={(key) => {
                            setCreated(key);
                            void queryClient.invalidateQueries({ queryKey: ['api-keys', projectUuid] });
                        }}
                    />

                    <section className="mt-8">
                        <h2 className="mb-3 text-[11px] font-semibold uppercase tracking-wide text-ink-400">
                            Clés existantes
                        </h2>

                        <div className="divide-y divide-ink-100 overflow-hidden rounded-lg border border-ink-200 bg-white">
                            {data.data?.keys.length === 0 && (
                                <p className="px-4 py-6 text-center text-sm text-ink-400">
                                    Aucune clé. Créez-en une pour brancher une application.
                                </p>
                            )}

                            {data.data?.keys.map((key) => (
                                <div
                                    key={key.uuid}
                                    className={`flex flex-wrap items-center gap-3 px-4 py-3 ${key.isUsable ? '' : 'opacity-50'}`}
                                >
                                    <div className="min-w-40 flex-1">
                                        <p className="text-sm font-medium text-ink-800">{key.name}</p>
                                        <p className="font-mono text-[11px] text-ink-400">{key.prefix}…</p>
                                    </div>

                                    <span className="rounded bg-ink-100 px-1.5 py-0.5 text-[11px] text-ink-600">
                                        {key.environment}
                                    </span>

                                    <span className="font-mono text-[10px] text-ink-400">
                                        {key.scopes.join(' · ')}
                                    </span>

                                    {/* Une clé jamais utilisée est soit oubliée, soit
                                        remplacée sans avoir été révoquée. Dans les deux
                                        cas elle devrait disparaître. */}
                                    <span className="min-w-28 text-[11px] text-ink-400">
                                        {key.revokedAt !== null
                                            ? 'révoquée'
                                            : key.lastUsedAt === null
                                              ? 'jamais utilisée'
                                              : `vue le ${new Date(key.lastUsedAt).toLocaleDateString('fr-FR')}`}
                                    </span>

                                    {key.isUsable && (
                                        <button
                                            onClick={() => revoke.mutate(key.uuid)}
                                            className="rounded px-2 py-1 text-xs text-ink-400 hover:bg-red-50 hover:text-red-700"
                                        >
                                            Révoquer
                                        </button>
                                    )}
                                </div>
                            ))}
                        </div>
                    </section>

                    <GettingStarted project={stats.data?.project ?? ''} />
                </div>
            </div>
        </div>
    );
}

function SecretBanner({ created, onDismiss }: { created: CreatedApiKey; onDismiss: () => void }) {
    const [copied, setCopied] = useState(false);

    return (
        <div className="mt-6 rounded-lg border-2 border-amber-300 bg-amber-50 p-5">
            <p className="text-sm font-medium text-amber-900">{created.warning}</p>

            <div className="mt-3 flex items-center gap-2">
                <code className="flex-1 select-all break-all rounded border border-amber-200 bg-white px-3 py-2 font-mono text-xs text-ink-900">
                    {created.secret}
                </code>
                <button
                    onClick={() => {
                        void navigator.clipboard?.writeText(created.secret);
                        setCopied(true);
                    }}
                    className="shrink-0 rounded-md bg-amber-600 px-3 py-2 text-xs font-medium text-white hover:bg-amber-700"
                >
                    {copied ? 'Copié' : 'Copier'}
                </button>
            </div>

            <p className="mt-3 text-xs text-amber-800">
                Elle n'est pas stockée en clair : la réafficher est impossible. Si vous la perdez,
                révoquez-la et créez-en une nouvelle.
            </p>

            <button onClick={onDismiss} className="mt-3 text-xs text-amber-700 underline-offset-4 hover:underline">
                J'ai copié la clé
            </button>
        </div>
    );
}

function CreateKeyForm({
    projectUuid,
    environments,
    scopes,
    onCreated,
}: {
    projectUuid: string;
    environments: string[];
    scopes: string[];
    onCreated: (key: CreatedApiKey) => void;
}) {
    const [name, setName] = useState('');
    const [environment, setEnvironment] = useState('');
    const [selected, setSelected] = useState<string[]>(['translations:read']);
    const [error, setError] = useState<string | null>(null);

    const create = useMutation({
        mutationFn: () =>
            api.createApiKey(projectUuid, {
                name,
                environment: environment || (environments[0] ?? ''),
                scopes: selected,
            }),
        onSuccess: (key) => {
            setError(null);
            setName('');
            onCreated(key);
        },
        onError: (caught) => setError(humanMessage(caught)),
    });

    return (
        <form
            onSubmit={(e) => {
                e.preventDefault();
                create.mutate();
            }}
            className="mt-6 rounded-lg border border-ink-200 bg-white p-5 shadow-sm"
        >
            <h2 className="mb-4 text-sm font-medium text-ink-800">Créer une clé</h2>

            <div className="flex flex-wrap gap-3">
                <input
                    required
                    value={name}
                    onChange={(e) => setName(e.target.value)}
                    placeholder="CI application web"
                    className="min-w-56 flex-1 rounded-md border border-ink-300 px-3 py-2 text-sm outline-none focus:border-accent"
                />

                <select
                    value={environment || environments[0] || ''}
                    onChange={(e) => setEnvironment(e.target.value)}
                    className="rounded-md border border-ink-300 bg-white px-2 py-2 text-sm outline-none focus:border-accent"
                >
                    {environments.map((slug) => (
                        <option key={slug} value={slug}>
                            {slug}
                        </option>
                    ))}
                </select>

                <button
                    type="submit"
                    disabled={create.isPending || selected.length === 0}
                    className="rounded-md bg-accent px-4 py-2 text-sm font-medium text-white hover:bg-indigo-700 disabled:opacity-60"
                >
                    {create.isPending ? 'Création…' : 'Créer'}
                </button>
            </div>

            <p className="mt-2 text-xs text-ink-400">
                Le nom est ce qui permettra de savoir quoi révoquer dans six mois.
            </p>

            <div className="mt-4">
                <p className="mb-1.5 text-xs font-medium text-ink-600">Permissions</p>
                <div className="flex flex-wrap gap-1.5">
                    {scopes.map((scope) => {
                        const on = selected.includes(scope);
                        const isWrite = scope.includes('write') || scope.includes('publish');

                        return (
                            <button
                                key={scope}
                                type="button"
                                onClick={() =>
                                    setSelected((prev) =>
                                        on ? prev.filter((s) => s !== scope) : [...prev, scope],
                                    )
                                }
                                className={`rounded px-2 py-1 font-mono text-[11px] transition-colors ${
                                    on
                                        ? isWrite
                                            ? 'bg-amber-600 text-white'
                                            : 'bg-accent text-white'
                                        : 'bg-ink-100 text-ink-600 hover:bg-ink-200'
                                }`}
                            >
                                {scope}
                            </button>
                        );
                    })}
                </div>
                {/* Les scopes d'écriture sont d'une autre couleur : une clé de
                    production ne devrait en porter aucun, et l'écart visuel rend
                    l'erreur difficile à commettre sans la voir. */}
                <p className="mt-2 text-xs text-ink-400">
                    Une clé de production n'a besoin que de lecture. Les permissions d'écriture
                    (en orange) sont réservées aux clés de développement et d'intégration continue.
                </p>
            </div>

            {error !== null && (
                <p role="alert" className="mt-4 rounded-md bg-red-50 px-3 py-2 text-sm text-red-700">
                    {error}
                </p>
            )}
        </form>
    );
}

function GettingStarted({ project }: { project: string }) {
    return (
        <section className="mt-8 rounded-lg border border-ink-200 bg-white p-5">
            <h2 className="mb-3 text-sm font-medium text-ink-800">Brancher une application</h2>

            <ol className="space-y-4 text-sm text-ink-700">
                <li>
                    <p className="font-medium">1. Installer le CLI</p>
                    <Snippet>{`curl -sSL https://tq-slator.internal/tqs.phar -o /usr/local/bin/tqs\nchmod +x /usr/local/bin/tqs`}</Snippet>
                </li>
                <li>
                    <p className="font-medium">2. Lier le dépôt</p>
                    <Snippet>{`export TQS_API_KEY=tqs_…\ntqs init`}</Snippet>
                    <p className="mt-1 text-xs text-ink-400">
                        Projet, environnement, plateformes et langues sont déduits de la clé.
                        Le fichier <code className="font-mono">tqs.config.json</code> produit se
                        committe — il ne contient aucun secret.
                    </p>
                </li>
                <li>
                    <p className="font-medium">3. Envoyer les clés du code</p>
                    <Snippet>{`tqs push --dry-run   # voir le diff\ntqs push             # appliquer`}</Snippet>
                </li>
                <li>
                    <p className="font-medium">4. Récupérer les traductions en intégration continue</p>
                    <Snippet>{`tqs pull\ntqs pull --check              # échoue si des fichiers ne sont pas commités\ntqs status --fail-under=80    # échoue si une langue passe sous 80 %`}</Snippet>
                </li>
            </ol>

            <p className="mt-4 text-xs text-ink-400">
                Les fichiers récupérés sont commités dans votre dépôt : votre production ne dépend
                donc jamais de la disponibilité de TQ-Slator. Projet visé :{' '}
                <code className="font-mono">{project}</code>
            </p>
        </section>
    );
}

function Snippet({ children }: { children: string }) {
    return (
        <pre className="mt-1.5 overflow-x-auto rounded bg-ink-900 px-3 py-2 font-mono text-xs leading-relaxed text-ink-100">
            {children}
        </pre>
    );
}
