"use client";

import { useState } from "react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useT } from "@/i18n";
import { useCan } from "@/features/auth/use-can";
import { friendlyErrorMessage } from "@/lib/errors";
import { useFieldErrors } from "@/lib/use-field-errors";
import { queryKeys } from "@/lib/query-keys";
import { updateStoreClient } from "@/services/store-clients";
import type { StoreClient } from "@/types/store";

/**
 * A store's configuration, corrected by support on its behalf.
 *
 * The shop normally does this itself from its own portal. This exists for when it cannot: the
 * owner is the person who left, or the callback URL is wrong in a way that only shows up in our
 * delivery log.
 *
 * The URL is **not** validated here beyond being non-empty. The server applies the SSRF rule —
 * https, a public host, standard port, no credentials — and duplicating a security rule in the
 * browser invites the two copies to drift, with the weaker one deciding. A refusal comes back as
 * a field error and is shown against the input.
 */
export function StoreConfiguration({ store }: { store: StoreClient }) {
  const t = useT();
  const { can } = useCan();
  const queryClient = useQueryClient();

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

  const [name, setName] = useState(store.name);
  const [webhookUrl, setWebhookUrl] = useState(store.webhook_url ?? "");
  const [allowedIps, setAllowedIps] = useState((store.allowed_ips ?? []).join("\n"));
  const [currency, setCurrency] = useState(store.default_currency);
  const [timezone, setTimezone] = useState(store.timezone);
  // Every field the server can refuse, kept apart. This used to pin any refusal to the callback
  // URL, which sent whoever read it to the wrong box when the currency or an IP was the problem.
  const fields = useFieldErrors({
    only: ["name", "webhook_url", "allowed_ips", "default_currency", "timezone"],
    collapse: ["allowed_ips"],
  });

  const save = useMutation({
    mutationFn: () =>
      updateStoreClient(store.uuid, {
        name,
        webhook_url: webhookUrl.trim() === "" ? null : webhookUrl.trim(),
        allowed_ips: allowedIps
          .split("\n")
          .map((line) => line.trim())
          .filter((line) => line !== ""),
        default_currency: currency,
        timezone,
      }),
    onSuccess: () => {
      fields.reset();
      toast.success(t("stores.saved"));
      void queryClient.invalidateQueries({
        queryKey: queryKeys.storeClients.detail(store.uuid),
      });
    },
    onMutate: fields.reset,
    onError: (error) => {
      // The SSRF refusal — a callback URL pointing inside our own network — names `webhook_url`,
      // and every other rule names its own field too. Each is shown where it was typed rather
      // than as a toast that disappears before somebody works out which field it meant.
      if (!fields.capture(error)) toast.error(friendlyErrorMessage(error, t));
    },
  });

  return (
    <Card className="p-5">
      <h3 className="text-sm font-semibold text-foreground">{t("stores.configuration")}</h3>
      <p className="mt-1 text-xs text-muted-foreground">{t("stores.configurationHint")}</p>

      <div className="mt-4 grid gap-4 sm:grid-cols-2">
        <div className="space-y-1.5">
          <Label htmlFor="store-name">{t("stores.title")}</Label>
          <Input
            id="store-name"
            value={name}
            onChange={(e) => setName(e.target.value)}
            disabled={!canManage}
            aria-invalid={fields.get("name") !== undefined}
          />
          {fields.get("name") ? (
            <p className="text-xs text-destructive">{fields.get("name")}</p>
          ) : null}
        </div>

        <div className="space-y-1.5">
          <Label htmlFor="store-handle">{t("stores.handle")}</Label>
          {/* Never editable — it is in our rate-limit keys and our logs. */}
          <Input id="store-handle" value={store.slug} disabled readOnly />
        </div>

        <div className="space-y-1.5 sm:col-span-2">
          <Label htmlFor="store-webhook">{t("stores.callbackUrl")}</Label>
          <Input
            id="store-webhook"
            value={webhookUrl}
            onChange={(e) => setWebhookUrl(e.target.value)}
            placeholder="https://…"
            disabled={!canManage}
            aria-invalid={fields.get("webhook_url") !== undefined}
          />
          <p className="text-xs text-muted-foreground">{t("stores.urlMustBePublic")}</p>
          {fields.get("webhook_url") ? (
            <p className="text-xs text-destructive">{fields.get("webhook_url")}</p>
          ) : null}
        </div>

        <div className="space-y-1.5 sm:col-span-2">
          <Label htmlFor="store-ips">{t("stores.allowedIps")}</Label>
          <textarea
            id="store-ips"
            value={allowedIps}
            onChange={(e) => setAllowedIps(e.target.value)}
            disabled={!canManage}
            rows={3}
            className="w-full rounded-md border bg-background p-2 text-sm disabled:opacity-60"
          />
          <p className="text-xs text-muted-foreground">{t("stores.allowedIpsHint")}</p>
          {/* One textarea here, a list to the server, which refuses a bad entry by its index
              (`allowed_ips.2`) — collapsed onto the control that holds every line. */}
          {fields.get("allowed_ips") ? (
            <p className="text-xs text-destructive">{fields.get("allowed_ips")}</p>
          ) : null}
        </div>

        <div className="space-y-1.5">
          <Label htmlFor="store-currency">{t("stores.currency")}</Label>
          <Input
            id="store-currency"
            value={currency}
            onChange={(e) => setCurrency(e.target.value.toUpperCase())}
            maxLength={3}
            disabled={!canManage}
            aria-invalid={fields.get("default_currency") !== undefined}
          />
          {fields.get("default_currency") ? (
            <p className="text-xs text-destructive">{fields.get("default_currency")}</p>
          ) : null}
        </div>

        <div className="space-y-1.5">
          <Label htmlFor="store-timezone">{t("stores.timezone")}</Label>
          <Input
            id="store-timezone"
            value={timezone}
            onChange={(e) => setTimezone(e.target.value)}
            disabled={!canManage}
            aria-invalid={fields.get("timezone") !== undefined}
          />
          {fields.get("timezone") ? (
            <p className="text-xs text-destructive">{fields.get("timezone")}</p>
          ) : null}
        </div>
      </div>

      {canManage ? (
        <div className="mt-4">
          <Button onClick={() => save.mutate()} disabled={save.isPending}>
            {save.isPending ? t("common.saving") : t("common.save")}
          </Button>
        </div>
      ) : null}
    </Card>
  );
}
