"use client";

import { useState } from "react";
import { toast } from "sonner";
import { KeyRound, Copy, Check, Loader2, TriangleAlert, Trash2 } from "lucide-react";
import { useT, useLocale } from "@/shared/i18n/client";
import { formatDate } from "@/shared/lib/format-date";
import { useApiMutation } from "@/presentation/hooks/use-api-mutation";
import { useApiQuery } from "@/presentation/hooks/use-api-query";
import type { GenerateMcpTokenPayload, McpCredential, McpTokenResult } from "@/domain/entities/mcp-token";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/presentation/components/ui/dialog";
import { Button } from "@/presentation/components/ui/button";
import { Input } from "@/presentation/components/ui/input";
import { Label } from "@/presentation/components/ui/label";
import { Separator } from "@/presentation/components/ui/separator";

interface McpTokenDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  /** Display name of the target company/user, shown in the description. */
  entityLabel: string;
  /** container.{company|user}Repository.generateMcpToken(id, payload) */
  generate: (payload: GenerateMcpTokenPayload) => Promise<McpTokenResult>;
  /** container.{company|user}Repository.listMcpTokens(id) */
  list: () => Promise<McpCredential[]>;
  /** container.{company|user}Repository.revokeMcpToken(id, credentialId) */
  revoke: (credentialId: number) => Promise<void>;
}

const STATUS_STYLES: Record<McpCredential["status"], string> = {
  active: "border-emerald-200 bg-emerald-50 text-emerald-700 dark:border-emerald-900 dark:bg-emerald-950/40 dark:text-emerald-300",
  expired: "border-slate-200 bg-slate-100 text-slate-600 dark:border-slate-800 dark:bg-slate-900/40 dark:text-slate-300",
  revoked: "border-red-200 bg-red-50 text-red-700 dark:border-red-900 dark:bg-red-950/40 dark:text-red-300",
};

/**
 * MCP-token management dialog — the token analogue of impersonation.
 *
 * Lists the target's existing MCP service credentials (with soft-revoke), and
 * generates new ones: an optional tuning form → the issued credentials
 * (client_id + client_secret shown ONCE, access_token, URLs) with per-field
 * copy buttons. Shared by the companies and users pages.
 */
export default function McpTokenDialog({ open, onOpenChange, entityLabel, generate, list, revoke }: McpTokenDialogProps) {
  const t = useT();
  const locale = useLocale();
  const [result, setResult] = useState<McpTokenResult | null>(null);
  const [name, setName] = useState("");
  const [ttlMinutes, setTtlMinutes] = useState("");
  const [expiresInDays, setExpiresInDays] = useState("");
  const [copiedKey, setCopiedKey] = useState<string | null>(null);
  const [confirmRevokeId, setConfirmRevokeId] = useState<number | null>(null);

  const creds = useApiQuery(() => list(), { enabled: open, deps: [open] });

  const gen = useApiMutation(
    (payload: GenerateMcpTokenPayload) => generate(payload),
    { successMessage: t.mcpToken.toastGenerated, onSuccess: (data) => { setResult(data); void creds.refetch(); } }
  );

  const revokeMut = useApiMutation(
    (credentialId: number) => revoke(credentialId),
    { successMessage: t.mcpToken.toastRevoked, onSuccess: () => { setConfirmRevokeId(null); void creds.refetch(); } }
  );

  const reset = () => {
    setResult(null);
    setName("");
    setTtlMinutes("");
    setExpiresInDays("");
    setCopiedKey(null);
    setConfirmRevokeId(null);
  };

  const handleOpenChange = (next: boolean) => {
    if (!next) reset();
    onOpenChange(next);
  };

  const handleGenerate = () => {
    const payload: GenerateMcpTokenPayload = {};
    if (name.trim()) payload.name = name.trim();
    const ttl = parseInt(ttlMinutes, 10);
    if (!Number.isNaN(ttl)) payload.ttl_minutes = ttl;
    const days = parseInt(expiresInDays, 10);
    if (!Number.isNaN(days)) payload.expires_in_days = days;
    void gen.mutate(payload);
  };

  const copy = (value: string, key: string) => {
    void navigator.clipboard.writeText(value);
    setCopiedKey(key);
    toast.success(t.mcpToken.copied);
    setTimeout(() => setCopiedKey((k) => (k === key ? null : k)), 1500);
  };

  const copyAll = () => {
    if (!result) return;
    const block = [
      `MCP URL: ${result.mcp_url}`,
      `Token endpoint: ${result.token_endpoint}`,
      `client_id: ${result.client_id}`,
      `client_secret: ${result.client_secret}`,
      `access_token: ${result.access_token}`,
    ].join("\n");
    copy(block, "all");
  };

  const field = (label: string, value: string, key: string, hint?: string) => (
    <div className="space-y-1">
      <Label className="text-xs">{label}</Label>
      <div className="flex items-center gap-2">
        <code className="flex-1 min-w-0 truncate rounded-md border bg-muted px-2 py-1.5 text-xs font-mono">{value}</code>
        <Button
          type="button"
          variant="outline"
          size="icon"
          className="h-8 w-8 flex-shrink-0"
          onClick={() => copy(value, key)}
          aria-label={t.mcpToken.copy}
        >
          {copiedKey === key ? <Check className="w-3.5 h-3.5 text-emerald-500" /> : <Copy className="w-3.5 h-3.5" />}
        </Button>
      </div>
      {hint && <p className="text-xs text-muted-foreground">{hint}</p>}
    </div>
  );

  const statusBadge = (status: McpCredential["status"]) => (
    <span className={`inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] font-semibold ${STATUS_STYLES[status]}`}>
      {status === "active" ? t.mcpToken.statusActive : status === "expired" ? t.mcpToken.statusExpired : t.mcpToken.statusRevoked}
    </span>
  );

  return (
    <Dialog open={open} onOpenChange={handleOpenChange}>
      <DialogContent className="max-w-lg max-h-[85vh] overflow-y-auto">
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2">
            <KeyRound className="w-4 h-4" />
            {t.mcpToken.dialogTitle}
          </DialogTitle>
          <DialogDescription>{t.mcpToken.dialogDescription(entityLabel)}</DialogDescription>
        </DialogHeader>

        {result ? (
          <div className="space-y-4">
            <div className="flex items-start gap-2 rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800 dark:border-amber-900 dark:bg-amber-950/40 dark:text-amber-300">
              <TriangleAlert className="w-4 h-4 flex-shrink-0 mt-0.5" />
              <span>{t.mcpToken.warning}</span>
            </div>

            {field(t.mcpToken.clientId, result.client_id, "client_id")}
            {field(t.mcpToken.clientSecret, result.client_secret, "client_secret", t.mcpToken.clientSecretHint)}
            {field(t.mcpToken.accessToken, result.access_token, "access_token", t.mcpToken.accessTokenHint(Math.round(result.expires_in / 60)))}

            <Separator />

            {field(t.mcpToken.mcpUrl, result.mcp_url, "mcp_url")}
            {field(t.mcpToken.tokenEndpoint, result.token_endpoint, "token_endpoint")}

            <div className="rounded-md bg-muted/50 px-3 py-2 text-xs text-muted-foreground space-y-1">
              <p className="font-medium text-foreground">{t.mcpToken.usageTitle}</p>
              <p>{t.mcpToken.usageBody}</p>
            </div>

            <DialogFooter>
              <Button variant="outline" onClick={copyAll}>{t.mcpToken.copyAll}</Button>
              <Button onClick={() => setResult(null)}>{t.mcpToken.done}</Button>
            </DialogFooter>
          </div>
        ) : (
          <div className="space-y-4">
            {/* Existing credentials */}
            <div className="space-y-2">
              <p className="text-sm font-medium">{t.mcpToken.existingTitle}</p>
              {creds.loading && !creds.data ? (
                <div className="flex items-center gap-2 py-3 text-sm text-muted-foreground">
                  <Loader2 className="w-4 h-4 animate-spin" /> {t.common.loading}
                </div>
              ) : !creds.data || creds.data.length === 0 ? (
                <p className="py-2 text-sm text-muted-foreground">{t.mcpToken.emptyList}</p>
              ) : (
                <div className="space-y-2">
                  {creds.data.map((cred) => (
                    <div key={cred.id} className="flex items-center justify-between gap-2 rounded-md border px-3 py-2">
                      <div className="min-w-0">
                        <div className="flex items-center gap-2">
                          <span className="text-sm font-medium truncate">{cred.name}</span>
                          {statusBadge(cred.status)}
                        </div>
                        <p className="text-xs text-muted-foreground truncate font-mono">{cred.client_id}</p>
                        <p className="text-xs text-muted-foreground">
                          {t.mcpToken.createdAtLabel} {formatDate(cred.created_at, locale)}
                          {" · "}
                          {t.mcpToken.lastUsedLabel}: {cred.last_used_at ? formatDate(cred.last_used_at, locale) : t.mcpToken.neverUsed}
                        </p>
                      </div>
                      {cred.status !== "revoked" && (
                        confirmRevokeId === cred.id ? (
                          <div className="flex flex-shrink-0 items-center gap-1">
                            <Button
                              size="sm"
                              variant="destructive"
                              disabled={revokeMut.loading}
                              onClick={() => void revokeMut.mutate(cred.id)}
                            >
                              {revokeMut.loading && <Loader2 className="w-3.5 h-3.5 mr-1 animate-spin" />}
                              {t.mcpToken.confirmRevoke}
                            </Button>
                            <Button size="sm" variant="outline" onClick={() => setConfirmRevokeId(null)}>{t.common.cancel}</Button>
                          </div>
                        ) : (
                          <Button
                            size="icon"
                            variant="ghost"
                            className="h-8 w-8 flex-shrink-0 text-destructive"
                            onClick={() => setConfirmRevokeId(cred.id)}
                            aria-label={t.mcpToken.revoke}
                          >
                            <Trash2 className="w-4 h-4" />
                          </Button>
                        )
                      )}
                    </div>
                  ))}
                </div>
              )}
            </div>

            <Separator />

            {/* Generate a new credential */}
            <div className="space-y-3">
              <p className="text-sm font-medium">{t.mcpToken.newSectionTitle}</p>
              <div className="space-y-2">
                <Label htmlFor="mcp-name">{t.mcpToken.nameLabel}</Label>
                <Input id="mcp-name" value={name} onChange={(e) => setName(e.target.value)} placeholder={t.mcpToken.namePlaceholder} />
              </div>
              <div className="grid grid-cols-2 gap-4">
                <div className="space-y-2">
                  <Label htmlFor="mcp-ttl">{t.mcpToken.ttlLabel}</Label>
                  <Input id="mcp-ttl" type="number" inputMode="numeric" min={5} max={1440} value={ttlMinutes} onChange={(e) => setTtlMinutes(e.target.value)} placeholder="60" />
                  <p className="text-xs text-muted-foreground">{t.mcpToken.ttlHint}</p>
                </div>
                <div className="space-y-2">
                  <Label htmlFor="mcp-expires">{t.mcpToken.expiresLabel}</Label>
                  <Input id="mcp-expires" type="number" inputMode="numeric" min={1} value={expiresInDays} onChange={(e) => setExpiresInDays(e.target.value)} placeholder="—" />
                  <p className="text-xs text-muted-foreground">{t.mcpToken.expiresHint}</p>
                </div>
              </div>
            </div>

            <DialogFooter>
              <Button variant="outline" onClick={() => handleOpenChange(false)}>{t.common.cancel}</Button>
              <Button onClick={handleGenerate} disabled={gen.loading}>
                {gen.loading && <Loader2 className="w-4 h-4 mr-2 animate-spin" />}
                {t.mcpToken.generate}
              </Button>
            </DialogFooter>
          </div>
        )}
      </DialogContent>
    </Dialog>
  );
}
