import { useMemo } from 'react';
import {
  Badge,
  Group,
  Paper,
  ScrollArea,
  Text,
  Timeline,
  Tooltip,
} from '@mantine/core';
import {
  IconFileUpload,
  IconMessage,
  IconArrowRight,
  IconUserCheck,
} from '@tabler/icons-react';
import { useTranslation } from 'react-i18next';
import {
  STATUS_COLORS,
  STATUS_LABELS,
  type ApplicationDetail,
} from '@ema-platform/api';
import { useDateDisplayer } from '@ema-platform/shared';

type EntryKind = 'status' | 'remark' | 'upload' | 'assignment';

interface ActivityEntry {
  id: string;
  kind: EntryKind;
  at: string;
  actor: string;
  title: string;
  detail?: string;
  color?: string;
}

const ICONS: Record<EntryKind, typeof IconArrowRight> = {
  status: IconArrowRight,
  remark: IconMessage,
  upload: IconFileUpload,
  assignment: IconUserCheck,
};

/**
 * Chronological record of everything that has happened to an application.
 *
 * Merged client-side from the three collections the detail endpoint already
 * returns — status transitions, officer remarks and document uploads. There is
 * no single activity-feed endpoint, so this is assembled rather than fetched;
 * the trade-off is that it can only show what the detail payload carries, and
 * notifications sent to the applicant are not among them.
 */
export function ActivityRail({ detail }: { detail: ApplicationDetail }) {
  const { t } = useTranslation();
  const showDate = useDateDisplayer();

  const entries = useMemo<ActivityEntry[]>(() => {
    const merged: ActivityEntry[] = [];

    for (const history of detail.history ?? []) {
      // A transition that does not move the status is a workflow control
      // (assignment, escalation), not a decision — labelled as such so the
      // trail does not read as "Under Review → Under Review".
      const isAssignment = history.fromStatus === history.toStatus;
      merged.push({
        id: `status-${history.id}`,
        kind: isAssignment ? 'assignment' : 'status',
        at: history.createdAt,
        actor: history.actorName ?? t('review.activity.system', 'System'),
        title: isAssignment
          ? t(`review.events.${history.event}`, {
              defaultValue: history.event,
            })
          : `${
              history.fromStatus
                ? t(`queue.statusValues.${history.fromStatus}`, STATUS_LABELS[history.fromStatus])
                : '—'
            } → ${t(`queue.statusValues.${history.toStatus}`, STATUS_LABELS[history.toStatus])}`,
        detail: history.remark ?? undefined,
        color: STATUS_COLORS[history.toStatus],
      });
    }

    for (const remark of detail.remarks ?? []) {
      merged.push({
        id: `remark-${remark.id}`,
        kind: 'remark',
        at: remark.createdAt,
        actor: t('review.activity.officer', 'Officer'),
        title: t('review.activity.remarkOn', {
          target: remark.targetKey,
          defaultValue: 'Correction requested on {{target}}',
        }),
        detail: remark.remark,
        color: remark.resolvedAt ? 'teal' : 'orange',
      });
    }

    for (const attachment of detail.attachments ?? []) {
      const file = attachment.files?.[0];
      if (!file) continue;
      merged.push({
        id: `upload-${attachment.id}`,
        kind: 'upload',
        at: attachment.createdAt ?? detail.application.createdAt,
        actor: t('review.activity.applicant', 'Applicant'),
        title: t('review.activity.uploaded', {
          document: attachment.documentKey,
          defaultValue: 'Uploaded {{document}}',
        }),
        detail: file.originalName,
        color: 'blue',
      });
    }

    // Newest first: an officer opening a review wants the latest state, not
    // the application's origin story.
    return merged.sort(
      (a, b) => new Date(b.at).getTime() - new Date(a.at).getTime(),
    );
  }, [detail, t]);

  if (entries.length === 0) {
    return (
      <Paper withBorder p="md">
        <Text size="sm" c="dimmed">
          {t('review.activity.empty', 'No activity recorded yet.')}
        </Text>
      </Paper>
    );
  }

  return (
    <Paper withBorder p="md" h="100%">
      <Group justify="space-between" mb="sm">
        <Text fw={600} size="sm">
          {t('review.activity.title', 'Activity & audit trail')}
        </Text>
        <Badge variant="light" size="sm">
          {entries.length}
        </Badge>
      </Group>

      <ScrollArea.Autosize mah={520} type="hover" offsetScrollbars>
        <Timeline bulletSize={20} lineWidth={2}>
          {entries.map((entry) => {
            const EntryIcon = ICONS[entry.kind];
            return (
              <Timeline.Item
                key={entry.id}
                bullet={<EntryIcon size={12} />}
                color={entry.color}
                title={
                  <Text size="xs" fw={600}>
                    {entry.title}
                  </Text>
                }
              >
                <Group gap={4} wrap="nowrap">
                  <Text size="xs" c="dimmed" truncate>
                    {entry.actor}
                  </Text>
                  <Text size="xs" c="dimmed">
                    ·
                  </Text>
                  <Tooltip label={showDate(entry.at)} withArrow>
                    <Text size="xs" c="dimmed">
                      {showDate(entry.at.slice(0, 10))}
                    </Text>
                  </Tooltip>
                </Group>
                {entry.detail && (
                  <Text size="xs" mt={2}>
                    {entry.detail}
                  </Text>
                )}
              </Timeline.Item>
            );
          })}
        </Timeline>
      </ScrollArea.Autosize>
    </Paper>
  );
}
