import {
  ActionIcon,
  Avatar,
  Badge,
  Button,
  Divider,
  Group,
  Menu,
  Paper,
  Text,
  Tooltip,
  rem,
} from '@mantine/core';
import { IconDots, IconAlertTriangle } from '@tabler/icons-react';
import { useTranslation } from 'react-i18next';
import { STATUS_COLORS, STATUS_LABELS, type LicenseStatus } from '@ema-platform/api';
import type { ActionId, ResolvedAction } from '../config/actions';
import type { SlaState } from '../sla';

interface DecisionBarProps {
  status: LicenseStatus;
  assigneeName?: string | null;
  sla?: SlaState;
  actions: ResolvedAction[];
  busyAction?: ActionId | null;
  onAction: (action: ResolvedAction) => void;
}

/**
 * The single place decisions are taken.
 *
 * Sticky to the bottom of the viewport and full workspace width, so it is
 * reachable at any scroll depth — the actions used to sit in a right-hand
 * column that scrolled away, meaning an officer reading the last document had
 * to scroll back up to act on it.
 *
 * Layout follows the action tiers: workflow controls left, the decision right,
 * everything else in the overflow menu. At most one filled button, so where to
 * look is never ambiguous.
 */
export function DecisionBar({
  status,
  assigneeName,
  sla,
  actions,
  busyAction,
  onAction,
}: DecisionBarProps) {
  const { t } = useTranslation();

  const workflow = actions.filter((a) => a.tier === 'workflow');
  // Three is the cap: past that the bar stops reading as a decision and starts
  // reading as a toolbar. The rest stay reachable in the overflow menu.
  const primary = actions.filter((a) => a.tier === 'primary').slice(0, 3);
  const overflowPrimary = actions.filter((a) => a.tier === 'primary').slice(3);
  const secondary = [
    ...overflowPrimary,
    ...actions.filter((a) => a.tier === 'secondary'),
  ];
  const destructive = actions.filter((a) => a.tier === 'destructive');

  return (
    <Paper
      withBorder
      shadow="md"
      px="lg"
      py="sm"
      style={{
        position: 'sticky',
        bottom: 0,
        zIndex: 60,
        borderRadius: 0,
        marginInline: `calc(-1 * var(--mantine-spacing-lg))`,
        background: 'var(--mantine-color-body)',
      }}
      role="region"
      aria-label={t('review.decisionBar', 'Decision bar')}
    >
      {/* Wraps rather than overflows: at narrow widths the nowrap row pushed
          the workflow buttons past the viewport edge, so Assign, Escalate and
          Hold were simply not there. Wrapping drops them onto a second line
          instead of off the screen. */}
      <Group justify="space-between" wrap="wrap" gap="sm">
        {/* Left: where the application stands, and who has it. */}
        <Group gap="sm" wrap="wrap" style={{ minWidth: 0, flex: '1 1 auto' }}>
          <Badge color={STATUS_COLORS[status]} variant="light" size="lg">
            {t(`queue.statusValues.${status}`, STATUS_LABELS[status])}
          </Badge>

          {assigneeName && (
            <Group gap={6} wrap="nowrap">
              <Avatar size={24} radius="xl" color="blue">
                {assigneeName.slice(0, 2).toUpperCase()}
              </Avatar>
              <Text size="sm" c="dimmed" truncate>
                {assigneeName}
              </Text>
            </Group>
          )}

          {sla && sla.state !== 'untracked' && (
            <Tooltip label={sla.tooltip} withArrow>
              <Badge
                color={sla.color}
                variant="light"
                // Never colour alone: the label carries the same meaning for
                // anyone who cannot distinguish the hues.
                leftSection={
                  sla.state === 'breached' ? <IconAlertTriangle size={12} /> : undefined
                }
              >
                {sla.label}
              </Badge>
            </Tooltip>
          )}

          {workflow.length > 0 && <Divider orientation="vertical" />}

          {workflow.map((action) => (
            <ActionButton
              key={action.id}
              action={action}
              busy={busyAction === action.id}
              onAction={onAction}
              size="xs"
            />
          ))}
        </Group>

        {/* Right: the decision. */}
        <Group gap="xs" wrap="wrap" justify="flex-end" style={{ flex: '0 1 auto' }}>
          {primary.map((action) => (
            <ActionButton
              key={action.id}
              action={action}
              busy={busyAction === action.id}
              onAction={onAction}
              size="sm"
            />
          ))}

          {(secondary.length > 0 || destructive.length > 0) && (
            <Menu position="top-end" withinPortal shadow="md" width={240}>
              <Menu.Target>
                <ActionIcon
                  variant="default"
                  size="lg"
                  aria-label={t('review.moreActions', 'More actions')}
                >
                  <IconDots size={18} />
                </ActionIcon>
              </Menu.Target>
              <Menu.Dropdown>
                {secondary.map((action) => (
                  <MenuAction key={action.id} action={action} onAction={onAction} />
                ))}
                {destructive.length > 0 && (
                  <>
                    <Menu.Divider />
                    <Menu.Label>
                      {t('review.irreversible', 'Cannot be undone')}
                    </Menu.Label>
                    {destructive.map((action) => (
                      <MenuAction
                        key={action.id}
                        action={action}
                        onAction={onAction}
                        color="red"
                      />
                    ))}
                  </>
                )}
              </Menu.Dropdown>
            </Menu>
          )}
        </Group>
      </Group>
    </Paper>
  );
}

interface ActionButtonProps {
  action: ResolvedAction;
  busy: boolean;
  size: 'xs' | 'sm';
  onAction: (action: ResolvedAction) => void;
}

/**
 * A disabled button always says why.
 *
 * Mantine strips pointer events from a disabled button, so the Tooltip has to
 * wrap a span — otherwise the one case where the explanation matters is the
 * one case it never appears.
 */
function ActionButton({ action, busy, size, onAction }: ActionButtonProps) {
  const { t } = useTranslation();
  const button = (
    <Button
      size={size}
      variant={
        action.emphasis === 'filled'
          ? 'filled'
          : action.emphasis === 'subtle'
            ? 'default'
            : 'light'
      }
      color={action.color}
      loading={busy}
      disabled={!action.enabled}
      style={{ flexShrink: 0 }}
      onClick={() => onAction(action)}
    >
      {t(action.labelKey)}
    </Button>
  );

  if (action.enabled) return button;

  return (
    <Tooltip
      label={action.disabledReason}
      withArrow
      position="top"
      multiline
      w={280}
    >
      <span style={{ display: 'inline-flex', cursor: 'not-allowed' }}>{button}</span>
    </Tooltip>
  );
}

function MenuAction({
  action,
  onAction,
  color,
}: {
  action: ResolvedAction;
  onAction: (action: ResolvedAction) => void;
  color?: string;
}) {
  const { t } = useTranslation();
  const item = (
    <Menu.Item
      color={color}
      disabled={!action.enabled}
      onClick={() => onAction(action)}
    >
      {t(action.labelKey)}
    </Menu.Item>
  );
  if (action.enabled) return item;
  return (
    <Tooltip
      label={action.disabledReason}
      withArrow
      position="left"
      multiline
      w={280}
    >
      <div>{item}</div>
    </Tooltip>
  );
}

export const DECISION_BAR_HEIGHT = rem(60);
