"use client";

import { useState } from "react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { Copy, KeyRound, ShieldOff } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { useI18n, useT } from "@/i18n";
import { useCan } from "@/features/auth/use-can";
import { formatDateTime } from "@/lib/format";
import { friendlyErrorMessage } from "@/lib/errors";
import { queryKeys } from "@/lib/query-keys";
import { issueStoreToken, revokeStoreTokens } from "@/services/store-clients";
import type { StoreClient } from "@/types/store";

/**
 * The store's machine credential — the token its *servers* use, not the password its staff
 * sign in with.
 *
 * Two rules this component exists to honour:
 *
 *  - **The plaintext is shown once.** It is held in component state and nowhere else: not in the
 *    query cache, not in storage, and never re-fetchable. Closing the dialog loses it, which is
 *    the point.
 *  - **Revoking is an emergency.** It is the answer to a leaked token, so it is one click behind
 *    a confirmation rather than buried, and the copy says plainly that portal access survives —
 *    otherwise somebody hesitates, wondering whether they are about to lock the shop out entirely.
 */
export function StoreCredentials({ store }: { store: StoreClient }) {
  const t = useT();
  const { locale } = useI18n();
  const { can } = useCan();
  const queryClient = useQueryClient();

  const [issuedToken, setIssuedToken] = useState<string | null>(null);
  const [confirming, setConfirming] = useState<"issue" | "revoke" | null>(null);

  const canManage = can("store_clients.manage");

  const refresh = () =>
    void queryClient.invalidateQueries({ queryKey: queryKeys.storeClients.detail(store.uuid) });

  const issue = useMutation({
    mutationFn: () => issueStoreToken(store.uuid),
    onSuccess: (response) => {
      setConfirming(null);
      setIssuedToken(response.Model?.token ?? null);
      toast.success(t("stores.tokenIssued"));
      refresh();
    },
    onError: (error) => toast.error(friendlyErrorMessage(error, t)),
  });

  const revoke = useMutation({
    mutationFn: () => revokeStoreTokens(store.uuid),
    onSuccess: () => {
      setConfirming(null);
      toast.success(t("stores.tokensRevoked"));
      refresh();
    },
    onError: (error) => toast.error(friendlyErrorMessage(error, t)),
  });

  const copyToken = async () => {
    if (!issuedToken) return;
    try {
      await navigator.clipboard.writeText(issuedToken);
      toast.success(t("stores.copied"));
    } catch {
      // Clipboard access can be refused; the value is on screen to copy by hand either way.
      toast.error(friendlyErrorMessage(new Error("clipboard"), t));
    }
  };

  const previousValidUntil = store.secrets.previous_valid_until;

  return (
    <Card className="p-5">
      <div className="flex items-start justify-between gap-4">
        <div>
          <h3 className="flex items-center gap-2 text-sm font-semibold text-foreground">
            <KeyRound className="h-4 w-4" aria-hidden />
            {t("stores.credentials")}
          </h3>
          <p className="mt-1 text-xs text-muted-foreground">{t("stores.credentialsHint")}</p>
        </div>
      </div>

      <dl className="mt-4 space-y-2 text-sm">
        <div className="flex justify-between gap-4">
          <dt className="text-muted-foreground">{t("stores.secretsRotated")}</dt>
          <dd>
            {store.secrets.has_secrets
              ? (formatDateTime(store.secrets.rotated_at, locale) ?? "—")
              : t("stores.noSecrets")}
          </dd>
        </div>

        {/*
          Only while a rotation's overlap window is open. Showing it always would be noise; showing
          it now tells support why two different secrets are both being accepted.
        */}
        {previousValidUntil ? (
          <div className="flex justify-between gap-4">
            <dt className="text-muted-foreground">{t("stores.previousSecretUntil")}</dt>
            <dd>{formatDateTime(previousValidUntil, locale)}</dd>
          </div>
        ) : null}
      </dl>

      {canManage ? (
        <div className="mt-4 flex flex-wrap gap-2">
          <Button size="sm" onClick={() => setConfirming("issue")}>
            {t("stores.issueToken")}
          </Button>
          <Button size="sm" variant="outline" onClick={() => setConfirming("revoke")}>
            <ShieldOff className="me-1 h-3 w-3" aria-hidden />
            {t("stores.revokeTokens")}
          </Button>
        </div>
      ) : null}

      <Dialog
        open={confirming !== null}
        onOpenChange={(next) => (next ? null : setConfirming(null))}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>
              {confirming === "issue" ? t("stores.issueTokenTitle") : t("stores.revokeTitle")}
            </DialogTitle>
            <DialogDescription>
              {confirming === "issue" ? t("stores.issueTokenBody") : t("stores.revokeBody")}
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button variant="ghost" onClick={() => setConfirming(null)}>
              {t("common.cancel")}
            </Button>
            <Button
              onClick={() => (confirming === "issue" ? issue.mutate() : revoke.mutate())}
              disabled={issue.isPending || revoke.isPending}
            >
              {issue.isPending || revoke.isPending ? t("common.saving") : t("common.confirm")}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* The one place a plaintext credential is ever on screen. */}
      <Dialog open={issuedToken !== null} onOpenChange={(next) => (next ? null : setIssuedToken(null))}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>{t("stores.tokenIssued")}</DialogTitle>
            <DialogDescription>{t("stores.tokenOnce")}</DialogDescription>
          </DialogHeader>
          <div className="flex items-center gap-2">
            <code className="flex-1 overflow-x-auto rounded-md bg-muted p-3 text-xs">
              {issuedToken}
            </code>
            <Button size="sm" variant="outline" onClick={copyToken}>
              <Copy className="me-1 h-3 w-3" aria-hidden />
              {t("stores.copy")}
            </Button>
          </div>
          <DialogFooter>
            <Button onClick={() => setIssuedToken(null)}>{t("common.close")}</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </Card>
  );
}
