"use client";

/**
 * Promo access role — add / edit.
 *
 * One form for both: `roleId === "new"` creates, anything else loads and updates.
 * The two cases differ only in which request is sent on save, so splitting them
 * would duplicate the whole form.
 *
 * Everything is saved in a single request, unlike the earlier inline editor that
 * wrote each export mode as you toggled it — on a full page with a Save button,
 * per-change writes would be surprising.
 */

import {
  Badge,
  Button,
  Card,
  Container,
  Flex,
  Group,
  Paper,
  SegmentedControl,
  Skeleton,
  Stack,
  Text,
  Textarea,
  TextInput,
  ThemeIcon,
  Title,
} from "@mantine/core";
import { notifications } from "@mantine/notifications";
import {
  IconArrowLeft,
} from "@tabler/icons-react";
import { useEffect, useState } from "react";
import { Link, useNavigate } from "react-router";
import {
  createPromoAccessRole,
  getPromoAccessRole,
  savePromoAccessRole,
} from "@/lib/features/promo-access-roles/query";
import {
  EXPORT_SECTION_ORDER,
  type ExportMode,
  type ExportSectionKey,
} from "@/lib/features/access-list/types";
import { EXPORT_SECTIONS } from "@/lib/features/access-list/exportSections";
import {
  PromoAccessSelector,
  type SelectorCampaign,
  type SelectorCampaignCodeRow,
  type SelectorPromoCode,
} from "@/lib/features/promo-access-roles/PromoAccessSelector";
import type { AccessScope } from "@/lib/features/types";
import styles from "@/routes/promo-code-campaigns/_components/promo.module.css";

/*
 * Sections, shared with the Access List page.
 *
 * Previously a second copy of the same array, kept in step by hand. Sharing it
 * means a new export section shows up in both places at once, with the same label
 * and the same list of pages it governs.
 */
const SECTIONS = EXPORT_SECTIONS;

const MODES: Array<{ mode: ExportMode; label: string; color: string; hint: string }> =
  [
    {
      mode: "download",
      label: "Download",
      color: "blue",
      hint: "Downloads the file directly.",
    },
    {
      mode: "request",
      label: "Request",
      color: "orange",
      hint: "Needs super-admin approval, then emailed.",
    },
    {
      mode: "none",
      label: "None",
      color: "gray",
      hint: "No export at all.",
    },
  ];

function defaultModes(): Record<ExportSectionKey, ExportMode> {
  return Object.fromEntries(
    EXPORT_SECTION_ORDER.map((k) => [k, "download" as ExportMode]),
  ) as Record<ExportSectionKey, ExportMode>;
}

export default function PromoAccessRoleFormClientPage({
  roleId,
  accessScope,
  promoCodes,
  campaigns,
  campaignPromoCodeMap,
}: {
  roleId: string;
  accessScope: AccessScope;
  promoCodes: SelectorPromoCode[];
  campaigns: SelectorCampaign[];
  campaignPromoCodeMap: SelectorCampaignCodeRow[];
}) {
  const navigate = useNavigate();
  const isNew = roleId === "new";

  const [loading, setLoading] = useState(!isNew);
  const [saving, setSaving] = useState(false);
  const [name, setName] = useState("");
  const [description, setDescription] = useState("");
  const [modes, setModes] = useState<Record<ExportSectionKey, ExportMode>>(
    defaultModes(),
  );
  const [pickCampaigns, setPickCampaigns] = useState<Set<string>>(new Set());
  const [pickCodes, setPickCodes] = useState<Set<string>>(new Set());

  useEffect(() => {
    if (isNew) return;
    let cancelled = false;
    void getPromoAccessRole(roleId).then((res) => {
      if (cancelled) return;
      if (res.success && res.data) {
        setName(res.data.name);
        setDescription(res.data.description ?? "");
        setModes({ ...defaultModes(), ...res.data.exportModes });
        setPickCampaigns(new Set(res.data.campaignIds));
        setPickCodes(new Set(res.data.promoCodeIds));
      } else {
        notifications.show({ color: "red", message: res.message });
      }
      setLoading(false);
    });
    return () => {
      cancelled = true;
    };
  }, [isNew, roleId]);

  const canSave = accessScope.update && name.trim().length > 0 && !saving;

  const save = async () => {
    if (!canSave) return;
    setSaving(true);
    const payload = {
      name: name.trim(),
      description: description.trim() || undefined,
      exportModes: modes,
      campaignIds: Array.from(pickCampaigns),
      promoCodeIds: Array.from(pickCodes),
    };
    const res = isNew
      ? await createPromoAccessRole(payload)
      : await savePromoAccessRole(roleId, payload);
    setSaving(false);
    notifications.show({
      color: res.success ? "green" : "red",
      message: res.message,
    });
    // Back to the list on success, so it is obvious the work was committed.
    if (res.success) navigate("/admin/promo-access-roles");
  };

  if (loading) {
    return (
      <Container fluid px={0} py={0}>
        <Stack gap="md">
          <Skeleton height={32} width={260} radius="sm" />
          <Skeleton height={180} radius="md" />
          <Skeleton height={300} radius="md" />
        </Stack>
      </Container>
    );
  }

  return (
    <Container fluid px={0} py={0}>
      <Flex justify="space-between" align="center" wrap="wrap" gap="sm" mb="md">
        <Group gap="sm">
          <Button
            variant="subtle"
            size="compact-sm"
            leftSection={<IconArrowLeft size={15} />}
            component={Link}
            to="/admin/promo-access-roles"
          >
            Promo Code Roles
          </Button>
          <Title order={4}>{isNew ? "Create role" : "Edit role"}</Title>
        </Group>
        <Button onClick={() => void save()} loading={saving} disabled={!canSave}>
          {isNew ? "Create role" : "Save changes"}
        </Button>
      </Flex>

      <Card className={styles.sectionCard} p="md" mb="md">
        <Stack gap="sm">
          <TextInput
            label="Role name"
            placeholder="e.g. Reports Analyst"
            value={name}
            onChange={(e) => setName(e.currentTarget.value)}
            disabled={!accessScope.update}
            required
          />
          <Textarea
            label="Description"
            placeholder="What this role is for (optional)"
            value={description}
            onChange={(e) => setDescription(e.currentTarget.value)}
            disabled={!accessScope.update}
            autosize
            minRows={2}
          />
        </Stack>
      </Card>

      <Card className={styles.sectionCard} p="md" mb="md">
        <Text fw={600} size="sm" mb="xs">
          Export permissions
        </Text>
        <Stack gap={6}>
          {SECTIONS.map(({ key, label, pages, personalData, Icon }) => {
            const mode = modes[key] ?? "download";
            const meta = MODES.find((m) => m.mode === mode) ?? MODES[0];
            return (
              <Paper key={key} withBorder radius="md" p="xs">
                <Flex justify="space-between" align="center" gap="sm" wrap="wrap">
                  <Group gap={10} wrap="nowrap" style={{ minWidth: 0 }}>
                    <ThemeIcon
                      variant="light"
                      color={meta.color}
                      size="md"
                      radius="md"
                    >
                      <Icon size={16} />
                    </ThemeIcon>
                    <Stack gap={0} style={{ minWidth: 0 }}>
                      <Group gap={6} wrap="nowrap">
                        <Text size="sm" fw={500}>
                          {label}
                        </Text>
                        {/* Whoever builds a role should see which of its
                            permissions release member personal data. */}
                        {personalData && (
                          <Badge variant="light" color="grape" size="xs">
                            personal data
                          </Badge>
                        )}
                      </Group>
                      {/* The Excel buttons this row governs, so the role can be
                          checked against the console rather than guessed at. */}
                      <Text size="xs" c="dimmed" lineClamp={1}>
                        {pages}
                      </Text>
                      {/* What the current choice does, rather than a legend. */}
                      <Text size="xs" c="dimmed">
                        {meta.hint}
                      </Text>
                    </Stack>
                  </Group>
                  <SegmentedControl
                    size="xs"
                    value={mode}
                    disabled={!accessScope.update}
                    onChange={(v) =>
                      setModes((prev) => ({ ...prev, [key]: v as ExportMode }))
                    }
                    data={MODES.map((m) => ({ value: m.mode, label: m.label }))}
                    style={{ flexShrink: 0 }}
                  />
                </Flex>
              </Paper>
            );
          })}
        </Stack>
      </Card>

      <Card className={styles.sectionCard} p="md">
        <Text fw={600} size="sm" mb="xs">
          Campaigns &amp; promo codes
        </Text>
        {/* The same selector the member Access List uses, so the auto-grant rule
            (a campaign grants its codes) behaves identically in both places. */}
        <PromoAccessSelector
          promoCodes={promoCodes}
          campaigns={campaigns}
          campaignPromoCodeMap={campaignPromoCodeMap}
          selectedCampaignIds={pickCampaigns}
          selectedPromoCodeIds={pickCodes}
          disabled={!accessScope.update}
          onChange={({ campaignIds, promoCodeIds }) => {
            setPickCampaigns(campaignIds);
            setPickCodes(promoCodeIds);
          }}
        />
      </Card>
    </Container>
  );
}
