"use client";

/**
 * Member-module access for one console user.
 *
 * Assignment only: a user holds access roles and their effective access is the
 * union of them. There is deliberately no per-user capability editor — copying a
 * role's values onto a user went stale the moment the role changed, and couldn't
 * express holding two roles at once.
 */

import {
  assignMemberAccessRole,
  CAPABILITY_GROUPS,
  removeMemberAccess,
  unassignMemberAccessRole,
  type MemberAccess,
  type MemberAccessRole,
  type MemberAccessRow,
} from "@/lib/features/members/access";
import {
  ActionIcon,
  Alert,
  Avatar,
  Badge,
  Button,
  Card,
  Grid,
  Group,
  Select,
  Stack,
  Text,
  ThemeIcon,
  Title,
  Tooltip,
} from "@mantine/core";
import {
  IconAlertTriangle,
  IconArrowLeft,
  IconCheck,
  IconMinus,
  IconPlus,
  IconTrash,
  IconUserShield,
} from "@tabler/icons-react";
import { useMemo, useState } from "react";
import { Link, useNavigate, useRevalidator } from "react-router";
import { toast } from "sonner";

const MemberAccessUserClientPage: React.FC<{
  userId: string;
  row: MemberAccessRow | null;
  roles: MemberAccessRole[];
  assigned: MemberAccessRole[];
  effective?: MemberAccess;
}> = ({ userId, row, roles, assigned, effective }) => {
  const navigate = useNavigate();
  const revalidator = useRevalidator();
  const [roleId, setRoleId] = useState<string | null>(null);
  const [busy, setBusy] = useState(false);

  const assignedIds = useMemo(
    () => new Set(assigned.map((role) => role.id)),
    [assigned],
  );
  const assignable = roles.filter((role) => !assignedIds.has(role.id));
  const isSuperAdmin = Boolean(row?.is_super_admin);
  const name =
    [row?.first_name, row?.last_name].filter(Boolean).join(" ") || row?.email;
  const initials = (name ?? "?")
    .split(" ")
    .map((part) => part[0])
    .filter(Boolean)
    .slice(0, 2)
    .join("")
    .toUpperCase();

  const assign = async () => {
    if (!roleId) return;
    setBusy(true);
    const response = await assignMemberAccessRole(userId, roleId);
    setBusy(false);
    if (response?.success) {
      toast.success("Role assigned");
      setRoleId(null);
      revalidator.revalidate();
    } else {
      toast.error(response?.message ?? "Could not assign the role");
    }
  };

  const unassign = async (role: MemberAccessRole) => {
    const response = await unassignMemberAccessRole(userId, role.id);
    if (response?.success) {
      toast.success(`${role.name} removed`);
      revalidator.revalidate();
    } else {
      toast.error(response?.message ?? "Could not remove the role");
    }
  };

  const clearAll = async () => {
    const response = await removeMemberAccess(userId);
    if (response?.success) {
      toast.success("All member access removed");
      navigate("/admin/members/access");
    } else {
      toast.error(response?.message ?? "Failed to remove access");
    }
  };

  const slice =
    effective && !isSuperAdmin
      ? effective.account_type_ids.length === 0 &&
        effective.account_status_ids.length === 0
        ? "All accounts"
        : `${effective.account_type_ids.length || "all"} type(s) · ${
            effective.account_status_ids.length || "all"
          } status(es)`
      : "All accounts";

  return (
    <Stack gap="lg">
      <Group justify="space-between" align="center">
        <Group gap={10} align="center">
          <Avatar radius="xl" size={38} variant="light">
            {initials}
          </Avatar>
          <Stack gap={0}>
            <Group gap={6} align="center">
              <Title order={6}>{name ?? userId}</Title>
              {isSuperAdmin ? (
                <Badge variant="light" size="sm" radius={4}>
                  super admin
                </Badge>
              ) : null}
            </Group>
            <Text fz={12} c="dimmed">
              {row?.email}
            </Text>
          </Stack>
        </Group>
        <Button
          variant="default"
          leftSection={<IconArrowLeft size={16} />}
          component={Link}
          to="/admin/members/access"
        >
          Back
        </Button>
      </Group>

      {isSuperAdmin ? (
        <Alert variant="light" icon={<IconUserShield size={16} />}>
          Super admins always have every capability and are never restricted to
          a slice of the member base. Roles assigned here make no difference to
          them.
        </Alert>
      ) : row && row.has_module_access === false ? (
        <Alert
          color="orange"
          variant="light"
          icon={<IconAlertTriangle size={16} />}
          title="Members module not granted"
        >
          None of this user&apos;s console roles grants the Members module, so
          no role assigned here takes effect. Grant <b>Members: read</b> in
          Settings → Roles first.
        </Alert>
      ) : null}

      <Grid gutter="md">
        {/* Left: what is assigned, and the control to change it. */}
        <Grid.Col span={{ base: 12, lg: 7 }}>
          <Card withBorder radius="lg" p="md" h="100%">
            <Group justify="space-between" align="center" mb="sm">
              <Group gap={8} align="baseline">
                <Text fw={600} fz={14}>
                  Assigned roles
                </Text>
                <Text fz={12} c="dimmed">
                  {assigned.length} assigned
                </Text>
              </Group>
            </Group>

            {assigned.length === 0 ? (
              <Text fz="sm" c="dimmed" mb="md">
                No roles assigned — this user can open the accounts list and
                contact details, and nothing else inside the module.
              </Text>
            ) : (
              <Stack gap="xs" mb="md">
                {assigned.map((role) => {
                  const granted = CAPABILITY_GROUPS.flatMap((group) =>
                    group.capabilities
                      .filter((capability) => role[capability.key] === true)
                      .map((capability) => ({ ...capability, group })),
                  );
                  const scoped =
                    (role.account_type_ids?.length ?? 0) > 0 ||
                    (role.account_status_ids?.length ?? 0) > 0;
                  return (
                    <Card key={role.id} withBorder radius="md" p="sm">
                      <Group justify="space-between" wrap="nowrap" mb={6}>
                        <Group gap={6}>
                          <Text fz="sm" fw={600}>
                            {role.name}
                          </Text>
                          {scoped ? (
                            <Badge
                              variant="light"
                              color="gray"
                              size="xs"
                              radius={4}
                            >
                              scoped
                            </Badge>
                          ) : null}
                        </Group>
                        <Tooltip label="Remove this role">
                          <ActionIcon
                            variant="subtle"
                            color="red"
                            onClick={() => void unassign(role)}
                            aria-label={`Remove ${role.name}`}
                          >
                            <IconMinus size={15} />
                          </ActionIcon>
                        </Tooltip>
                      </Group>
                      <Group gap={4} wrap="wrap">
                        {granted.length === 0 ? (
                          <Text fz={12} c="dimmed">
                            Grants nothing
                          </Text>
                        ) : (
                          granted.map((capability) => (
                            <Badge
                              key={capability.key}
                              variant="light"
                              color={
                                capability.group.key === "actions"
                                  ? "orange"
                                  : undefined
                              }
                              size="xs"
                              radius={4}
                            >
                              {capability.label}
                            </Badge>
                          ))
                        )}
                      </Group>
                    </Card>
                  );
                })}
              </Stack>
            )}

            <Group align="flex-end" gap="sm">
              <Select
                label="Assign a role"
                placeholder={
                  roles.length === 0
                    ? "No roles created yet"
                    : assignable.length === 0
                      ? "All roles assigned"
                      : "Choose a role…"
                }
                data={assignable.map((role) => ({
                  value: role.id,
                  label: role.name,
                }))}
                value={roleId}
                onChange={setRoleId}
                disabled={assignable.length === 0}
                searchable
                style={{ flex: 1 }}
              />
              <Button
                leftSection={<IconPlus size={15} />}
                disabled={!roleId || busy}
                loading={busy}
                onClick={() => void assign()}
              >
                Assign
              </Button>
            </Group>
          </Card>
        </Grid.Col>

        {/* Right: what the server will actually enforce. */}
        <Grid.Col span={{ base: 12, lg: 5 }}>
          <Card withBorder radius="lg" p="md" h="100%">
            <Text fw={600} fz={14}>
              Effective access
            </Text>
            <Text fz={12} c="dimmed" mb="sm">
              The union of the assigned roles — what the server enforces.
            </Text>

            <Stack gap="sm">
              {CAPABILITY_GROUPS.map((group) => (
                <Stack key={group.key} gap={4}>
                  <Text fz={10} c="dimmed" tt="uppercase" fw={700}>
                    {group.title}
                  </Text>
                  {group.capabilities.map((capability) => {
                    const on = isSuperAdmin || effective?.[capability.key];
                    return (
                      <Group key={capability.key} gap={8} wrap="nowrap">
                        <ThemeIcon
                          size={18}
                          radius="xl"
                          variant="light"
                          color={
                            on
                              ? group.key === "actions"
                                ? "orange"
                                : undefined
                              : "gray"
                          }
                        >
                          {on ? (
                            <IconCheck size={11} />
                          ) : (
                            <IconMinus size={11} />
                          )}
                        </ThemeIcon>
                        <Text fz="sm" c={on ? undefined : "dimmed"}>
                          {capability.label}
                        </Text>
                      </Group>
                    );
                  })}
                </Stack>
              ))}

              <Stack gap={2} mt={4}>
                <Text fz={10} c="dimmed" tt="uppercase" fw={700}>
                  Visible slice
                </Text>
                <Text fz="sm">{slice}</Text>
                <Text fz={11} c="dimmed">
                  A role with no slice keeps access unrestricted.
                </Text>
              </Stack>
            </Stack>
          </Card>
        </Grid.Col>
      </Grid>

      {assigned.length > 0 ? (
        <Group justify="flex-start">
          <Button
            variant="light"
            color="red"
            leftSection={<IconTrash size={14} />}
            onClick={() => void clearAll()}
          >
            Remove all roles
          </Button>
        </Group>
      ) : null}
    </Stack>
  );
};

export default MemberAccessUserClientPage;
