"use client";

import {
  Button,
  Center,
  Group,
  Loader,
  Paper,
  PasswordInput,
  Stack,
  Text,
  ThemeIcon,
  Title,
} from "@mantine/core";
import { IconLinkOff, IconLock } from "@tabler/icons-react";
import { useCallback, useEffect, useState } from "react";
import DashboardFrame from "../_components/DashboardFrame";
import classes from "../_components/dashboard.module.css";

/**
 * Public share-link viewer — rendered outside the console's auth gate.
 *
 * The share token in the URL is the credential. It is used to build the serve
 * URL and to call unlock, and is never displayed, never logged, and never
 * handed to the sandboxed frame as data.
 *
 * All the "why is this link dead" logic stays server-side (prompt 4 collapses
 * unknown / revoked / expired / draft / no-version into one identical 404).
 * This UI mirrors that: any non-serviceable state gets the same generic
 * message, so a prober learns nothing here either.
 */

type Gate = "probing" | "password" | "ready" | "unavailable";

const PublicDashboardViewer: React.FC<{ token: string }> = ({ token }) => {
  const serveSrc = `/api/proxy/v1/public/dashboards/${token}/serve/`;

  const [gate, setGate] = useState<Gate>("probing");
  const [password, setPassword] = useState("");
  const [submitting, setSubmitting] = useState(false);
  const [badPassword, setBadPassword] = useState(false);
  /** Display-only, derived from the URL for support/traceability. Not the token. */
  const [label, setLabel] = useState("Shared preview");

  /*
   * Probe before rendering the frame.
   *
   * The frame is cross-origin, so it cannot tell us whether it got a 200, a
   * 401 or a 404. We ask once ourselves and branch on the status:
   *   200 → render      401 → password gate      anything else → unavailable
   */
  const probe = useCallback(async () => {
    setGate("probing");
    try {
      const res = await fetch(serveSrc, {
        method: "GET",
        credentials: "include",
        headers: { Accept: "text/html" },
      });
      if (res.ok) {
        setGate("ready");
        return;
      }
      if (res.status === 401) {
        setGate("password");
        return;
      }
      setGate("unavailable");
    } catch {
      setGate("unavailable");
    }
  }, [serveSrc]);

  useEffect(() => {
    void probe();
    // A short, non-identifying label. The raw token never appears in the UI.
    setLabel(`Shared preview · ${token.slice(0, 4)}…`);
  }, [probe, token]);

  const submitPassword = async () => {
    setSubmitting(true);
    setBadPassword(false);
    try {
      const res = await fetch(`/api/proxy/v1/public/dashboards/${token}/unlock`, {
        method: "POST",
        credentials: "include",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ password }),
      });
      if (res.ok) {
        // The unlock cookie is scoped to this link id and set by the API;
        // re-probing now succeeds. We never store or inspect it ourselves.
        setPassword("");
        await probe();
        return;
      }
      if (res.status === 401) {
        setBadPassword(true);
        return;
      }
      setGate("unavailable");
    } catch {
      setGate("unavailable");
    } finally {
      setSubmitting(false);
    }
  };

  // ---------------------------------------------------------------- states
  if (gate === "probing") {
    return (
      <Center h="100dvh">
        <Loader size="sm" />
      </Center>
    );
  }

  if (gate === "unavailable") {
    return (
      <Center h="100dvh" px="md">
        <Stack align="center" gap="xs" maw={380}>
          <ThemeIcon size={54} radius="xl" variant="light" color="gray">
            <IconLinkOff size={26} />
          </ThemeIcon>
          <Title order={4} mt={4}>
            This link isn't available
          </Title>
          {/* Deliberately says nothing about why. */}
          <Text size="sm" c="dimmed" ta="center">
            The link may have expired, been revoked, or never existed. Please ask
            whoever shared it with you for a new one.
          </Text>
        </Stack>
      </Center>
    );
  }

  if (gate === "password") {
    return (
      <Center h="100dvh" px="md">
        <Paper withBorder radius="lg" p="xl" w={380} shadow="sm">
          <Stack gap="md">
            <Stack align="center" gap={6}>
              <ThemeIcon size={46} radius="xl" variant="light" color="gray">
                <IconLock size={22} />
              </ThemeIcon>
              <Title order={4} mt={4}>
                Password required
              </Title>
              <Text size="sm" c="dimmed" ta="center">
                This dashboard is protected. Enter the password you were given.
              </Text>
            </Stack>
            <PasswordInput
              value={password}
              onChange={(e) => {
                setPassword(e.currentTarget.value);
                setBadPassword(false);
              }}
              onKeyDown={(e) => {
                if (e.key === "Enter" && password) void submitPassword();
              }}
              placeholder="Password"
              radius="md"
              autoFocus
              error={badPassword ? "Incorrect password" : undefined}
              aria-label="Dashboard password"
            />
            <Button
              radius="md"
              fullWidth
              loading={submitting}
              disabled={!password}
              onClick={() => void submitPassword()}
            >
              View dashboard
            </Button>
          </Stack>
        </Paper>
      </Center>
    );
  }

  // ---------------------------------------------------------------- viewer
  return (
    <div className={classes.viewerShell}>
      {/*
        Preview chrome: no console nav, no admin controls, no version switcher.
        The public path never honours ?v= — the backend serves the current
        published version and nothing else.
      */}
      <div className={classes.viewerChrome}>
        <Group gap="xs">
          <Text fw={600} size="sm">
            Dashboard preview
          </Text>
        </Group>
        <Text size="xs" c="dimmed">
          Shared securely · read-only
        </Text>
      </div>

      <DashboardFrame serveSrc={serveSrc} mode="public" title="Shared dashboard" />

      {/* Non-interactive, low-opacity, corner-anchored — never covers content. */}
      <div className={classes.watermark} aria-hidden="true">
        {label}
      </div>
    </div>
  );
};

export default PublicDashboardViewer;
