'use client';
import { FunctionComponent } from 'react';
import Box from '@mui/material/Box';
import Skeleton from '@mui/material/Skeleton';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import { useLocale, useTranslations } from 'next-intl';
import AppButton from '@/components/common/AppButton';
import { useTicketThread } from '@/services/tickets';
import type { TicketAuthorRole, TicketMessage } from '@/services/tickets/types';
import { formatDaySeparator, formatShamsiDate, formatShamsiTime } from '@/utils';
import { authorLabelKey } from './authorLabel';
import MessageBubble from './MessageBubble';
import { useThreadScroll } from './useThreadScroll';

export interface TicketMessageListProps {
  ticketId: number;
  /** Re-mutates a failed send with the same `clientMessageId` (never a duplicate bubble — §3.3). */
  onRetry: (message: TicketMessage) => void;
  /** Discards a failed bubble and restores its text to the composer draft. */
  onDiscard: (message: TicketMessage) => void;
}

type MessageBlock =
  | { kind: 'separator'; key: string; label: string }
  | { kind: 'system'; key: string; message: TicketMessage }
  | { kind: 'group'; key: string; authorRole: TicketAuthorRole; isMine: boolean; messages: TicketMessage[] };

/** Groups messages into date separators, centered system events, and consecutive same-author bubbles. */
function buildBlocks(messages: TicketMessage[], locale: string, todayLabel: string, yesterdayLabel: string): MessageBlock[] {
  const blocks: MessageBlock[] = [];
  let lastDayKey: string | null = null;

  for (const message of messages) {
    const dayKey = formatShamsiDate(message.createdAt, locale);
    if (dayKey !== lastDayKey) {
      blocks.push({
        kind: 'separator',
        key: `sep-${message.clientMessageId ?? message.id}`,
        label: formatDaySeparator(message.createdAt, locale, todayLabel, yesterdayLabel),
      });
      lastDayKey = dayKey;
    }

    if (message.authorRole === 'system') {
      blocks.push({ kind: 'system', key: `sys-${message.clientMessageId ?? message.id}`, message });
      continue;
    }

    const last = blocks[blocks.length - 1];
    if (last?.kind === 'group' && last.authorRole === message.authorRole && last.isMine === message.isMine) {
      last.messages.push(message);
    } else {
      blocks.push({
        kind: 'group',
        key: `grp-${message.clientMessageId ?? message.id}`,
        authorRole: message.authorRole,
        isMine: message.isMine,
        messages: [message],
      });
    }
  }
  return blocks;
}

/**
 * The message list of a thread — a `select` over the ticket detail (`useTicketThread`), so it re-renders on a
 * new (optimistic) message without re-rendering the thread header. Reads as a **timeline**: centered Shamsi
 * date separators (امروز/دیروز/older date), consecutive same-author messages grouped under one author label,
 * `hh:mm`-only bubble stamps, and `system` messages as centered neutral event chips instead of bubbles.
 * Opens scrolled to the **newest** message and auto-scrolls on send/receive (`useThreadScroll`, §3.2), with a
 * floating "new message" pill when the viewer has scrolled up. Empty / skeleton / populated states. Never
 * renders an internal note — there are none in the user view (§5).
 * @component TicketMessageList
 */
const TicketMessageList: FunctionComponent<TicketMessageListProps> = ({ ticketId, onRetry, onDiscard }) => {
  const t = useTranslations('tickets');
  const locale = useLocale();
  const { data: messages, isLoading } = useTicketThread(ticketId);

  const lastMessage = messages?.[messages.length - 1];
  const { bottomRef, showNewMessagePill, scrollToNewest } = useThreadScroll(messages?.length ?? 0, lastMessage?.isMine ?? false);

  if (isLoading) {
    return (
      <Stack sx={{ gap: 1 }}>
        {[0, 1, 2].map((i) => (
          <Skeleton key={i} variant="rounded" height={56} sx={{ width: '70%', alignSelf: i % 2 ? 'flex-end' : 'flex-start' }} />
        ))}
      </Stack>
    );
  }

  if (!messages || messages.length === 0) {
    return (
      <Stack sx={{ gap: 0.5, alignItems: 'center', py: 4 }}>
        <Typography variant="subtitle2" sx={{ fontWeight: 700 }}>
          {t('thread_empty_title')}
        </Typography>
        <Typography variant="body2" sx={{ color: 'var(--bal-text-secondary)' }}>
          {t('thread_empty_body')}
        </Typography>
      </Stack>
    );
  }

  const blocks = buildBlocks(messages, locale, t('day_today'), t('day_yesterday'));

  return (
    <Box sx={{ position: 'relative' }}>
      <Stack sx={{ gap: 1.5 }}>
        {blocks.map((block) => {
          if (block.kind === 'separator') {
            return (
              <Typography
                key={block.key}
                variant="caption"
                sx={{ textAlign: 'center', color: 'var(--bal-text-secondary)', fontWeight: 700 }}
              >
                {block.label}
              </Typography>
            );
          }
          if (block.kind === 'system') {
            return (
              <Typography
                key={block.key}
                variant="caption"
                data-testid="system-event"
                sx={{
                  alignSelf: 'center',
                  color: 'var(--bal-text-secondary)',
                  bgcolor: 'var(--bal-divider)',
                  borderRadius: 10,
                  px: 1.5,
                  py: 0.5,
                }}
              >
                {block.message.body}
              </Typography>
            );
          }
          return (
            <Stack key={block.key} sx={{ gap: 0.25 }}>
              {block.messages.map((message, index) => (
                <MessageBubble
                  key={message.clientMessageId ?? String(message.id)}
                  message={message}
                  authorLabel={t(authorLabelKey(message.authorRole))}
                  showAuthorLabel={index === 0 && !message.isMine}
                  timeLabel={formatShamsiTime(message.createdAt, locale)}
                  sendingLabel={t('sending')}
                  failedLabel={t('send_failed')}
                  retryLabel={t('retry')}
                  discardLabel={t('discard_failed')}
                  onRetry={() => onRetry(message)}
                  onDiscard={() => onDiscard(message)}
                />
              ))}
            </Stack>
          );
        })}
        <Box ref={bottomRef} sx={{ height: 1 }} />
      </Stack>

      {showNewMessagePill ? (
        <Box
          sx={{
            position: 'sticky',
            bottom: 'calc(var(--bal-chrome-bottom, 0px) + 8px)',
            display: 'flex',
            justifyContent: 'center',
            pt: 1,
          }}
        >
          <AppButton
            variant="contained"
            color="primary"
            size="small"
            onClick={scrollToNewest}
            sx={{ borderRadius: 10, boxShadow: 'var(--bal-shadow-2)' }}
          >
            {t('new_message_pill')}
          </AppButton>
        </Box>
      ) : null}
    </Box>
  );
};

export default TicketMessageList;
