"use client";

import {
  Alert,
  Badge,
  Box,
  Button,
  Code,
  CopyButton,
  Divider,
  Drawer,
  FileButton,
  Group,
  Modal,
  Paper,
  PasswordInput,
  Select,
  Stack,
  Table,
  Tabs,
  Text,
  Textarea,
  TextInput,
  ThemeIcon,
  Timeline,
  Title,
  Tooltip,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { notifications } from "@mantine/notifications";
import {
  IconAlertTriangle,
  IconArrowBackUp,
  IconCheck,
  IconCopy,
  IconExternalLink,
  IconEye,
  IconHistory,
  IconLink,
  IconLock,
  IconPencil,
  IconPhoto,
  IconPlus,
  IconRocket,
  IconTrash,
  IconUsers,
} from "@tabler/icons-react";
import moment from "moment";
import { useState } from "react";
import { Link, useNavigate, useRevalidator } from "react-router";
import ConfirmAlert from "@/components/blocks/ConfirmAlert/confirmAlert";
import {
  createPublicLink,
  deleteDashboard,
  publishDashboard,
  revokePublicLink,
  rollbackDashboard,
  setDashboardAccess,
  updateDashboard,
  uploadDashboardCover,
  dashboardCoverUrl,
} from "@/lib/features/dashboard/action";
import type {
  CreatedPublicLink,
  DashboardDetail,
} from "@/lib/features/dashboard/types";
import AccessPicker, { type AccessMode } from "../_components/AccessPicker";
import BundleDropzone from "../_components/BundleDropzone";
import { coverArtFor } from "../_components/coverGradient";
import classes from "../_components/dashboard.module.css";

const mb = (bytes: string | number | null) =>
  bytes === null ? "—" : `${(Number(bytes) / 1024 / 1024).toFixed(2)} MB`;

const DashboardManagePage: React.FC<{ detail: DashboardDetail }> = ({ detail }) => {
  const navigate = useNavigate();
  const revalidator = useRevalidator();
  const refresh = () => revalidator.revalidate();

  const { dashboard, versions, isDashboardAdmin, accessList = [], publicLinks = [] } = detail;
  const art = coverArtFor(dashboard.slug, dashboard.name);
  const isPublished = dashboard.status === "published";

  const [busy, setBusy] = useState(false);
  const [uploadOpen, uploadHandlers] = useDisclosure(false);
  const [editOpen, editHandlers] = useDisclosure(false);
  const [deleteOpen, deleteHandlers] = useDisclosure(false);
  const [linkOpen, linkHandlers] = useDisclosure(false);
  const [coverFailed, setCoverFailed] = useState(false);

  const [name, setName] = useState(dashboard.name);
  const [description, setDescription] = useState(dashboard.description ?? "");
  const [accessMode, setAccessMode] = useState<AccessMode>("specific");
  const [accessIds, setAccessIds] = useState<string[]>(
    accessList.map((a) => a.console_user_id),
  );
  const [linkExpiry, setLinkExpiry] = useState<string>("never");
  const [linkPassword, setLinkPassword] = useState("");
  const [issued, setIssued] = useState<CreatedPublicLink | null>(null);

  const toast = (ok: boolean, title: string, message?: string) =>
    notifications.show({
      color: ok ? "teal" : "red",
      title,
      message: message ?? "",
      icon: ok ? <IconCheck size={16} /> : <IconAlertTriangle size={16} />,
    });

  const run = async (fn: () => Promise<{ success: boolean; message?: string }>, okTitle: string) => {
    setBusy(true);
    const res = await fn();
    setBusy(false);
    toast(res.success, res.success ? okTitle : "Something went wrong", res.message);
    if (res.success) refresh();
    return res.success;
  };

  const showCover = Boolean(dashboard.cover_image_path) && !coverFailed;

  return (
    <Stack gap="lg" py="md">
      {/* ------------------------------------------------------------ header */}
      <div className={classes.hero}>
        <Group className={classes.heroInner} justify="space-between" align="flex-start" wrap="wrap" gap="lg">
          <Group align="flex-start" gap="md" wrap="nowrap">
            <Box
              w={104}
              h={62}
              style={{ borderRadius: 10, overflow: "hidden", flexShrink: 0 }}
            >
              {showCover ? (
                <img
                  src={dashboardCoverUrl(dashboard.id)}
                  alt=""
                  onError={() => setCoverFailed(true)}
                  style={{ width: "100%", height: "100%", objectFit: "cover" }}
                />
              ) : (
                <div style={{ width: "100%", height: "100%", background: art.background }} />
              )}
            </Box>
            <Stack gap={4}>
              <Group gap="xs">
                <Title order={3}>{dashboard.name}</Title>
                <Badge size="sm" radius="sm" variant="filled" autoContrast
                  color={isPublished ? "teal.7" : "yellow.6"}>
                  {isPublished ? "Published" : "Draft"}
                </Badge>
              </Group>
              <Text size="sm" c="dimmed" maw={560}>
                {dashboard.description?.trim() || "No description provided."}
              </Text>
              <Group gap="lg" mt={2}>
                <Text size="xs" c="dimmed">
                  {dashboard.current_version_number
                    ? `Live: v${dashboard.current_version_number}`
                    : "No version published"}
                </Text>
                <Text size="xs" c="dimmed">
                  Updated {moment(dashboard.updated_at).fromNow()}
                </Text>
              </Group>
            </Stack>
          </Group>

          <Group gap="xs">
            {dashboard.current_version_id ? (
              <Tooltip label="Open the sandboxed viewer" withArrow>
                <Button
                  component={Link}
                  to={`/admin/dashboard/${dashboard.slug}/view`}
                  variant="default"
                  radius="md"
                  leftSection={<IconExternalLink size={15} />}
                >
                  Open dashboard
                </Button>
              </Tooltip>
            ) : (
              <Tooltip label="Publish a version first" withArrow>
                <Button variant="default" radius="md" disabled
                  leftSection={<IconExternalLink size={15} />}>
                  Open dashboard
                </Button>
              </Tooltip>
            )}
            {isDashboardAdmin && (
              <>
                <Button variant="default" radius="md" leftSection={<IconPencil size={15} />} onClick={editHandlers.open}>
                  Edit
                </Button>
                <Button radius="md" leftSection={<IconPlus size={15} />} onClick={uploadHandlers.open}>
                  Upload version
                </Button>
              </>
            )}
          </Group>
        </Group>
      </div>

      {!isDashboardAdmin ? (
        <Alert variant="light" color="gray" radius="md">
          <Text size="sm">
            You have view access to this dashboard. Management actions are
            available to dashboard managers.
          </Text>
        </Alert>
      ) : (
        <Tabs defaultValue="versions" radius="md" keepMounted={false}>
          <Tabs.List>
            <Tabs.Tab value="versions" leftSection={<IconHistory size={14} />}>
              Versions ({versions.length})
            </Tabs.Tab>
            <Tabs.Tab value="access" leftSection={<IconUsers size={14} />}>
              Access ({accessList.length})
            </Tabs.Tab>
            <Tabs.Tab value="links" leftSection={<IconLink size={14} />}>
              Public links ({publicLinks.length})
            </Tabs.Tab>
            <Tabs.Tab value="audit" leftSection={<IconEye size={14} />}>
              Activity
            </Tabs.Tab>
          </Tabs.List>

          {/* ------------------------------------------------------ versions */}
          <Tabs.Panel value="versions" pt="md">
            <Paper withBorder radius="md" p={0}>
              <Table highlightOnHover verticalSpacing="sm" horizontalSpacing="md">
                <Table.Thead>
                  <Table.Tr>
                    <Table.Th>Version</Table.Th>
                    <Table.Th>Entry point</Table.Th>
                    <Table.Th>Files</Table.Th>
                    <Table.Th>Size</Table.Th>
                    <Table.Th>Uploaded</Table.Th>
                    <Table.Th />
                  </Table.Tr>
                </Table.Thead>
                <Table.Tbody>
                  {versions.map((v) => {
                    const isCurrent = v.id === dashboard.current_version_id;
                    return (
                      <Table.Tr key={v.id}>
                        <Table.Td>
                          <Group gap={6}>
                            <Text size="sm" fw={isCurrent ? 700 : 500}>v{v.version_number}</Text>
                            {isCurrent && (
                              <Badge size="xs" radius="sm" variant="filled" color="teal.7">
                                Live
                              </Badge>
                            )}
                          </Group>
                        </Table.Td>
                        <Table.Td><Text size="xs" c="dimmed">{v.entry_point}</Text></Table.Td>
                        <Table.Td><Text size="xs">{v.file_count}</Text></Table.Td>
                        <Table.Td><Text size="xs">{mb(v.size_bytes)}</Text></Table.Td>
                        <Table.Td><Text size="xs" c="dimmed">{moment(v.created_at).format("DD MMM YYYY, HH:mm")}</Text></Table.Td>
                        <Table.Td>
                          <Group gap={6} justify="flex-end">
                            {!isCurrent && (
                              <>
                                <Button size="compact-xs" variant="light" radius="md" loading={busy}
                                  leftSection={<IconRocket size={12} />}
                                  onClick={() => run(() => publishDashboard(dashboard.id, v.id), `v${v.version_number} published`)}>
                                  Publish
                                </Button>
                                <Tooltip label="Make this the live version without changing status" withArrow>
                                  <Button size="compact-xs" variant="subtle" radius="md" loading={busy}
                                    leftSection={<IconArrowBackUp size={12} />}
                                    onClick={() => run(() => rollbackDashboard(dashboard.id, v.id), `Rolled back to v${v.version_number}`)}>
                                    Roll back
                                  </Button>
                                </Tooltip>
                              </>
                            )}
                          </Group>
                        </Table.Td>
                      </Table.Tr>
                    );
                  })}
                  {versions.length === 0 && (
                    <Table.Tr>
                      <Table.Td colSpan={6}>
                        <Text size="sm" c="dimmed" ta="center" py="lg">
                          No versions uploaded yet.
                        </Text>
                      </Table.Td>
                    </Table.Tr>
                  )}
                </Table.Tbody>
              </Table>
            </Paper>
            <Text size="xs" c="dimmed" mt="xs">
              Versions are immutable — old files stay in storage, so rolling back
              is instant and never re-uploads.
            </Text>
          </Tabs.Panel>

          {/* -------------------------------------------------------- access */}
          <Tabs.Panel value="access" pt="md">
            <Stack gap="md">
              <AccessPicker
                mode={accessMode}
                onModeChange={setAccessMode}
                selected={accessIds}
                onSelectedChange={setAccessIds}
              />
              <Group justify="flex-end">
                <Button radius="md" loading={busy}
                  onClick={() => run(() => setDashboardAccess(dashboard.id, accessIds), "Access list updated")}>
                  Save access list
                </Button>
              </Group>
              {accessList.length > 0 && (
                <Paper withBorder radius="md" p="sm">
                  <Text size="xs" c="dimmed" mb={6}>Currently granted</Text>
                  <Group gap={6}>
                    {accessList.map((a) => (
                      <Badge key={a.grant_id} variant="light" color="gray" radius="sm" size="sm">
                        {a.email}
                      </Badge>
                    ))}
                  </Group>
                </Paper>
              )}
            </Stack>
          </Tabs.Panel>

          {/* --------------------------------------------------- public links */}
          <Tabs.Panel value="links" pt="md">
            <Stack gap="md">
              <Group justify="space-between">
                <Text size="sm" c="dimmed">
                  Anyone with the link can view the current published version — no
                  console account needed.
                </Text>
                <Button radius="md" leftSection={<IconPlus size={15} />} onClick={linkHandlers.open}
                  disabled={!isPublished}>
                  Create link
                </Button>
              </Group>
              {!isPublished && (
                <Alert variant="light" color="yellow" radius="md">
                  <Text size="xs">Publish the dashboard before sharing it publicly.</Text>
                </Alert>
              )}
              <Paper withBorder radius="md" p={0}>
                <Table verticalSpacing="sm" horizontalSpacing="md">
                  <Table.Thead>
                    <Table.Tr>
                      <Table.Th>Created</Table.Th>
                      <Table.Th>Expires</Table.Th>
                      <Table.Th>Password</Table.Th>
                      <Table.Th>Views</Table.Th>
                      <Table.Th>Status</Table.Th>
                      <Table.Th />
                    </Table.Tr>
                  </Table.Thead>
                  <Table.Tbody>
                    {publicLinks.map((l) => (
                      <Table.Tr key={l.id}>
                        <Table.Td><Text size="xs">{moment(l.created_at).format("DD MMM YYYY")}</Text></Table.Td>
                        <Table.Td><Text size="xs">{l.expires_at ? moment(l.expires_at).format("DD MMM YYYY") : "Never"}</Text></Table.Td>
                        <Table.Td>
                          {l.has_password
                            ? <Badge size="xs" variant="light" color="blue" leftSection={<IconLock size={9} />}>Yes</Badge>
                            : <Text size="xs" c="dimmed">No</Text>}
                        </Table.Td>
                        <Table.Td><Text size="xs">{l.view_count}</Text></Table.Td>
                        <Table.Td>
                          <Badge size="xs" radius="sm" variant="light" color={l.is_revoked ? "red" : "teal"}>
                            {l.is_revoked ? "Revoked" : "Active"}
                          </Badge>
                        </Table.Td>
                        <Table.Td>
                          {!l.is_revoked && (
                            <Group justify="flex-end">
                              <Button size="compact-xs" variant="subtle" color="red" radius="md" loading={busy}
                                onClick={() => run(() => revokePublicLink(dashboard.id, l.id), "Link revoked")}>
                                Revoke
                              </Button>
                            </Group>
                          )}
                        </Table.Td>
                      </Table.Tr>
                    ))}
                    {publicLinks.length === 0 && (
                      <Table.Tr>
                        <Table.Td colSpan={6}>
                          <Text size="sm" c="dimmed" ta="center" py="lg">No public links yet.</Text>
                        </Table.Td>
                      </Table.Tr>
                    )}
                  </Table.Tbody>
                </Table>
              </Paper>
              <Text size="xs" c="dimmed">
                Link tokens are stored hashed — the full URL is shown once, at
                creation, and cannot be recovered afterwards. Revoking is
                permanent; the row is kept so view history survives.
              </Text>
            </Stack>
          </Tabs.Panel>

          {/* --------------------------------------------------------- audit */}
          <Tabs.Panel value="audit" pt="md">
            <Paper withBorder radius="md" p="lg">
              {detail.audit?.length ? (
                <Timeline active={-1} bulletSize={18} lineWidth={2}>
                  {detail.audit.map((a) => (
                    <Timeline.Item key={a.id} title={<Text size="sm" fw={600}>{a.action}</Text>}>
                      <Text size="xs" c="dimmed">
                        {a.actor_email ?? "system"} · {moment(a.created_at).format("DD MMM YYYY, HH:mm")}
                      </Text>
                      {a.metadata && (
                        <Code block mt={6} style={{ fontSize: 10 }}>
                          {JSON.stringify(a.metadata, null, 2)}
                        </Code>
                      )}
                    </Timeline.Item>
                  ))}
                </Timeline>
              ) : (
                <Text size="sm" c="dimmed" ta="center" py="lg">No activity recorded yet.</Text>
              )}
            </Paper>
          </Tabs.Panel>
        </Tabs>
      )}

      {isDashboardAdmin && (
        <>
          <Divider my="xs" />
          <Group justify="space-between">
            <Text size="xs" c="dimmed">
              Deleting removes every version, its files, all share links and all access grants.
            </Text>
            <Button variant="light" color="red" radius="md" leftSection={<IconTrash size={15} />}
              onClick={deleteHandlers.open}>
              Delete dashboard
            </Button>
          </Group>
        </>
      )}

      {/* --------------------------------------------------- upload version */}
      <Drawer opened={uploadOpen} onClose={uploadHandlers.close} position="right" size="lg"
        title={<Text fw={600}>Upload a new version</Text>}>
        <Stack gap="md">
          <BundleDropzone
            dashboardId={dashboard.id}
            mode="newVersion"
            onUploaded={(r) => {
              toast(true, `Version ${r.version.version_number} uploaded`, "Publish it from the Versions tab when you're ready.");
              uploadHandlers.close();
              refresh();
            }}
          />
          <Alert variant="light" color="gray" radius="md">
            <Text size="xs">
              A new version is stored but not made live. Publish it from the
              Versions tab when you're ready.
            </Text>
          </Alert>
        </Stack>
      </Drawer>

      {/* ------------------------------------------------------- edit meta */}
      <Modal opened={editOpen} onClose={editHandlers.close} title="Edit dashboard" centered radius="md">
        <Stack gap="md">
          <TextInput label="Name" value={name} onChange={(e) => setName(e.currentTarget.value)} radius="md" />
          <Textarea label="Description" value={description} autosize minRows={3} radius="md"
            onChange={(e) => setDescription(e.currentTarget.value)} />
          <Box>
            <Text size="sm" fw={500} mb={6}>Cover image</Text>
            <FileButton accept="image/png,image/jpeg,image/webp"
              onChange={async (f) => {
                if (!f) return;
                const ok = await run(() => uploadDashboardCover(dashboard.id, f), "Cover updated");
                if (ok) setCoverFailed(false);
              }}>
              {(props) => (
                <Button {...props} variant="default" radius="md" leftSection={<IconPhoto size={15} />} loading={busy}>
                  Replace cover
                </Button>
              )}
            </FileButton>
          </Box>
          <Group justify="flex-end">
            <Button variant="default" radius="md" onClick={editHandlers.close}>Cancel</Button>
            <Button radius="md" loading={busy}
              onClick={async () => {
                const ok = await run(
                  () => updateDashboard(dashboard.id, { name: name.trim(), description: description.trim() || null }),
                  "Dashboard updated",
                );
                if (ok) editHandlers.close();
              }}>
              Save
            </Button>
          </Group>
        </Stack>
      </Modal>

      {/* -------------------------------------------------- create link ---- */}
      <Modal opened={linkOpen} onClose={() => { linkHandlers.close(); setIssued(null); }}
        title={issued ? "Copy this link now" : "Create a public link"} centered radius="md">
        {issued ? (
          <Stack gap="md">
            <Alert variant="light" color="yellow" radius="md" icon={<IconAlertTriangle size={16} />}
              title="You will not see this again">
              <Text size="xs">
                Only a hash of this token is stored. If you lose the URL you must
                revoke this link and create a new one.
              </Text>
            </Alert>
            <Code block style={{ wordBreak: "break-all", fontSize: 11 }}>{issued.url}</Code>
            <Group justify="space-between">
              <CopyButton value={issued.url} timeout={2000}>
                {({ copied, copy }) => (
                  <Button radius="md" color={copied ? "teal" : undefined}
                    leftSection={copied ? <IconCheck size={15} /> : <IconCopy size={15} />} onClick={copy}>
                    {copied ? "Copied" : "Copy link"}
                  </Button>
                )}
              </CopyButton>
              <Button variant="default" radius="md"
                onClick={() => { linkHandlers.close(); setIssued(null); refresh(); }}>
                Done
              </Button>
            </Group>
          </Stack>
        ) : (
          <Stack gap="md">
            <Select label="Expires" value={linkExpiry} onChange={(v) => setLinkExpiry(v ?? "never")}
              allowDeselect={false} radius="md"
              data={[
                { value: "never", label: "Never" },
                { value: "7", label: "In 7 days" },
                { value: "30", label: "In 30 days" },
                { value: "90", label: "In 90 days" },
              ]} />
            <PasswordInput label="Password (optional)" placeholder="Leave blank for no password"
              value={linkPassword} onChange={(e) => setLinkPassword(e.currentTarget.value)} radius="md"
              description="Viewers must enter this before the dashboard loads." />
            <Group justify="flex-end">
              <Button variant="default" radius="md" onClick={linkHandlers.close}>Cancel</Button>
              <Button radius="md" loading={busy}
                onClick={async () => {
                  setBusy(true);
                  const res = await createPublicLink(dashboard.id, {
                    expiresAt: linkExpiry === "never"
                      ? null
                      : moment().add(Number(linkExpiry), "days").toISOString(),
                    password: linkPassword.trim() || null,
                  });
                  setBusy(false);
                  if (!res.success) { toast(false, "Could not create link", res.message); return; }
                  setIssued(res.data);
                  setLinkPassword("");
                }}>
                Create link
              </Button>
            </Group>
          </Stack>
        )}
      </Modal>

      <ConfirmAlert
        title="Delete this dashboard?"
        titleIcon={<ThemeIcon size={22} radius="xl" variant="light" color="red"><IconAlertTriangle size={13} /></ThemeIcon>}
        message={`"${dashboard.name}" and all ${versions.length} version(s), their files, ${publicLinks.length} share link(s) and ${accessList.length} access grant(s) will be removed. This cannot be undone.`}
        modalProps={{ opened: deleteOpen, onClose: deleteHandlers.close }}
        handleConfirm={async () => {
          deleteHandlers.close();
          const res = await deleteDashboard(dashboard.id);
          toast(res.success, res.success ? "Dashboard deleted" : "Could not delete", res.message);
          if (res.success) navigate("/admin/dashboard");
        }}
      />
    </Stack>
  );
};

export default DashboardManagePage;
