/**
 * `Settings → Deployment` (ticket #68) — turn IdeA Desktop into a server other
 * devices can reach, without a command line.
 *
 * Pure presentation over {@link useDeployment}; no `invoke()`, and no address is
 * ever derived here — LAN candidates and the upstream URL come from the backend
 * preview (`DesktopServerGateway`).
 *
 * Two UX invariants this screen exists to protect:
 *
 * - **The exposure mode is a decision, not a setting.** It is rendered as radio
 *   *cards* with plain-language consequences, never a technical select, because
 *   choosing wrong (proxy elsewhere, mode "on this computer") fails as a silent
 *   proxy timeout with no IdeA error to read.
 * - **The authorized-proxy field is not a listen address.** That confusion is
 *   the whole reason this screen is worded the way it is; the help text under
 *   the field says so explicitly.
 *
 * The pairing code is runtime-only: shown while running, never rendered into a
 * persisted field, never mixed with the upstream value.
 */

import { useState } from "react";

import type { ServerExposureMode } from "@/domain";
import { Button, Field, Input, Panel, cn } from "@/shared";
import { useDeployment } from "./useDeployment";

interface ModeOption {
  mode: ServerExposureMode;
  title: string;
  description: string;
}

/** The three exposure choices, in increasing order of reach. */
const MODE_OPTIONS: ModeOption[] = [
  {
    mode: "localOnly",
    title: "This computer only",
    description:
      "For using IdeA on this desktop only. Remote devices cannot connect.",
  },
  {
    mode: "remoteProxyLocal",
    title: "Remote access, proxy on this computer",
    description:
      "Use this when your HTTPS proxy runs on the same machine as IdeA Desktop.",
  },
  {
    mode: "remoteProxyOtherMachine",
    title: "Remote access, proxy on another machine",
    description:
      "Use this when the HTTPS proxy runs on another machine. IdeA will only accept traffic from that proxy.",
  },
];

const STATE_LABEL: Record<string, string> = {
  stopped: "Stopped",
  starting: "Starting…",
  running: "Running",
  stopping: "Stopping…",
  failed: "Failed",
};

/** Copy-to-clipboard button; degrades to disabled where the API is absent. */
function CopyButton({ value, label }: { value: string; label: string }) {
  const [copied, setCopied] = useState(false);
  const supported =
    typeof navigator !== "undefined" && Boolean(navigator.clipboard);
  return (
    <Button
      size="sm"
      variant="ghost"
      aria-label={label}
      disabled={!supported}
      onClick={() => {
        void navigator.clipboard.writeText(value).then(
          () => {
            setCopied(true);
            window.setTimeout(() => setCopied(false), 1500);
          },
          () => setCopied(false),
        );
      }}
    >
      {copied ? "Copied" : "Copy"}
    </Button>
  );
}

/** A read-only value the user is meant to copy elsewhere (never editable). */
function ReadOnlyValue({ value, copyLabel }: { value: string; copyLabel: string }) {
  return (
    <div className="flex items-center gap-2">
      <code className="flex-1 truncate rounded-md border border-border bg-raised px-2 py-1.5 font-mono text-xs text-content">
        {value}
      </code>
      <CopyButton value={value} label={copyLabel} />
    </div>
  );
}

export function DeploymentSettings() {
  const vm = useDeployment();

  if (!vm.ready || !vm.settings) {
    return (
      <Panel aria-label="deployment settings" title="Deployment">
        <p className="text-sm text-muted">Loading…</p>
      </Panel>
    );
  }

  const { settings, status } = vm;
  const running = status.state === "running";
  const remote = settings.mode !== "localOnly";
  const otherMachine = settings.mode === "remoteProxyOtherMachine";
  const transitioning = status.state === "starting" || status.state === "stopping";

  return (
    <div aria-label="deployment settings" className="flex flex-col gap-4">
      {/* ── Status ────────────────────────────────────────────────────────── */}
      <Panel
        title="Server"
        actions={
          running || status.state === "stopping" ? (
            <Button
              size="sm"
              onClick={() => void vm.stop()}
              disabled={vm.busy || transitioning}
            >
              Stop
            </Button>
          ) : (
            <Button
              size="sm"
              onClick={() => void vm.start()}
              disabled={vm.busy || transitioning}
            >
              Start
            </Button>
          )
        }
      >
        <div className="flex flex-col gap-2">
          <p className="flex items-center gap-2 text-sm">
            <span
              aria-hidden
              className={cn(
                "size-2 rounded-full",
                running && "bg-success",
                status.state === "failed" && "bg-danger",
                (status.state === "stopped" || transitioning) && "bg-faint",
              )}
            />
            <span className="text-content">{STATE_LABEL[status.state]}</span>
          </p>

          {status.localUrl && (
            <p className="text-xs text-muted">
              Local URL: <code className="font-mono text-content">{status.localUrl}</code>
            </p>
          )}
          {status.publicUrl && (
            <p className="text-xs text-muted">
              Public URL: <code className="font-mono text-content">{status.publicUrl}</code>
            </p>
          )}

          {/* A failure carries the backend's message: it is the correction. */}
          {status.state === "failed" && status.error && (
            <p role="alert" className="text-sm text-danger">
              {status.error.message}
            </p>
          )}
          {vm.actionError && (
            <p role="alert" className="text-sm text-danger">
              {vm.actionError}
            </p>
          )}
        </div>
      </Panel>

      {/* ── Exposure ──────────────────────────────────────────────────────── */}
      <Panel title="Exposure">
        <div className="flex flex-col gap-4">
          <div
            role="radiogroup"
            aria-label="exposure mode"
            className="flex flex-col gap-2"
          >
            {MODE_OPTIONS.map((option) => {
              const selected = settings.mode === option.mode;
              return (
                <label
                  key={option.mode}
                  className={cn(
                    "flex cursor-pointer gap-3 rounded-lg border p-3 transition-colors",
                    selected
                      ? "border-border-strong bg-raised"
                      : "border-border hover:bg-raised",
                  )}
                >
                  <input
                    type="radio"
                    name="exposure-mode"
                    className="mt-1"
                    checked={selected}
                    onChange={() => vm.setMode(option.mode)}
                  />
                  <span className="flex flex-col gap-1">
                    <span className="text-sm font-semibold text-content">
                      {option.title}
                    </span>
                    <span className="text-xs text-muted">{option.description}</span>
                  </span>
                </label>
              );
            })}
          </div>

          <Field label="Port">
            {({ id }) => (
              <Input
                id={id}
                type="number"
                value={String(settings.port)}
                onChange={(e) => vm.setPort(Number(e.target.value))}
              />
            )}
          </Field>

          {remote && (
            <Field label="Public origin" hint="Example: https://idea.example.com">
              {({ id, describedBy }) => (
                <Input
                  id={id}
                  aria-describedby={describedBy}
                  placeholder="https://idea.example.com"
                  value={settings.publicOrigin ?? ""}
                  onChange={(e) => vm.setPublicOrigin(e.target.value)}
                />
              )}
            </Field>
          )}

          {otherMachine && (
            <>
              {/* Addresses come from the backend probe — never invented here. */}
              <Field
                label="LAN address to bind"
                hint="The address on this machine that the proxy will connect to."
              >
                {({ id, describedBy }) =>
                  vm.candidateLanAddresses.length > 0 ? (
                    <select
                      id={id}
                      aria-describedby={describedBy}
                      className="rounded-md border border-border bg-surface px-2 py-1.5 text-sm text-content"
                      value={settings.lanBindAddress ?? ""}
                      onChange={(e) => vm.setLanBindAddress(e.target.value)}
                    >
                      <option value="">Select an address…</option>
                      {vm.candidateLanAddresses.map((address) => (
                        <option key={address} value={address}>
                          {address}
                        </option>
                      ))}
                    </select>
                  ) : (
                    <Input
                      id={id}
                      aria-describedby={describedBy}
                      placeholder="192.168.1.42"
                      value={settings.lanBindAddress ?? ""}
                      onChange={(e) => vm.setLanBindAddress(e.target.value)}
                    />
                  )
                }
              </Field>

              <Field
                label="Authorized proxy IP/CIDR"
                hint="This is not where IdeA listens. It is the machine allowed to contact IdeA."
              >
                {({ id, describedBy }) => (
                  <Input
                    id={id}
                    aria-describedby={describedBy}
                    placeholder="203.0.113.7 or 203.0.113.0/24"
                    value={settings.trustedProxies.join(", ")}
                    onChange={(e) => vm.setTrustedProxies(e.target.value)}
                  />
                )}
              </Field>

              <p className="rounded-md border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-warning">
                If your proxy is not on this computer, choose this mode.
                Otherwise the proxy may time out without an IdeA error.
              </p>
            </>
          )}

          {/* Warnings inform; they never block a start. */}
          {vm.warnings.map((warning) => (
            <p key={warning.code} className="text-xs text-warning">
              {warning.message}
            </p>
          ))}

          {vm.validationError && (
            <p role="alert" className="text-sm text-danger">
              {vm.validationError}
            </p>
          )}
        </div>
      </Panel>

      {/* ── Proxy setup: the upstream to paste, backend-provided ──────────── */}
      {remote && (
        <Panel title="Proxy setup">
          <div className="flex flex-col gap-2">
            <p className="text-xs text-muted">
              Point your HTTPS reverse proxy at this upstream.
            </p>
            {vm.upstreamUrl ? (
              <ReadOnlyValue value={vm.upstreamUrl} copyLabel="copy upstream url" />
            ) : (
              <p className="text-xs text-faint">
                Complete the settings above to get the upstream URL.
              </p>
            )}
          </div>
        </Panel>
      )}

      {/* ── Pairing: runtime-only secret, isolated from the upstream ──────── */}
      <Panel title="Pairing">
        {running && status.pairingCode ? (
          <div className="flex flex-col gap-2">
            <ReadOnlyValue value={status.pairingCode} copyLabel="copy pairing code" />
            <p className="text-xs text-muted">
              Temporary code. It disappears when the server stops. Do not save it
              in configuration files.
            </p>
          </div>
        ) : (
          <p className="text-sm text-muted">
            Start the server to generate a pairing code.
          </p>
        )}
      </Panel>
    </div>
  );
}
