import {
  ClearOutlined,
  CopyOutlined,
  ReloadOutlined,
  SearchOutlined
} from '@ant-design/icons';
import {
  Alert,
  App,
  Button,
  Card,
  Descriptions,
  Drawer,
  Grid,
  Input,
  List,
  Pagination,
  Result,
  Select,
  Skeleton,
  Space,
  Table,
  Tabs,
  Timeline,
  Typography
} from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useLocation, useNavigate, useParams, useSearchParams } from 'react-router-dom';

import { CodeBlock } from '../components/common/CodeBlock';
import { EmptyState } from '../components/common/EmptyState';
import { PageHeader } from '../components/common/PageHeader';
import { SectionCard } from '../components/common/SectionCard';
import { StatusPill } from '../components/common/StatusPill';
import { buildEventTimeline } from '../frontend/analytics-model.js';
import { useI18n } from '../frontend/i18n/react';
import { detailHistoryLocation, detailHistoryState } from '../frontend/navigation-state';
import { api } from '../frontend/services/api';
import type {
  DeliveryAttempt,
  DeliveryLogEntry,
  Domain,
  SendEvent,
  SendEventTimelineEntry,
  TrackingLink,
  WebhookDelivery
} from '../frontend/types';

interface EventFilters {
  page: number;
  pageSize: number;
  status?: string;
  domainId?: number;
  from?: string;
  to?: string;
  recipient?: string;
  q?: string;
}

interface EventPage {
  events: SendEvent[];
  total?: number;
  page?: number;
  pageSize?: number;
}

interface FilterDraft {
  from: string;
  to: string;
  domainId?: string;
  status?: string;
  recipient: string;
  q: string;
}

type DetailTab = 'attempts' | 'tracking' | 'webhooks' | 'raw';

export default function SendingLogs() {
  const { eventId } = useParams<{ eventId: string }>();
  const location = useLocation();
  const navigate = useNavigate();
  const [searchParams, setSearchParams] = useSearchParams();
  const queryKey = searchParams.toString();
  const { locale } = useI18n();
  const copy = locale.startsWith('en') ? enCopy : zhCopy;
  const { message } = App.useApp();
  const screens = Grid.useBreakpoint();
  const [domains, setDomains] = useState<Domain[]>([]);
  const [pageData, setPageData] = useState<EventPage | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');
  const [draft, setDraft] = useState<FilterDraft>(() => draftFromParams(searchParams));
  const [selected, setSelected] = useState<SendEvent | null>(null);
  const [detailLoading, setDetailLoading] = useState(false);
  const [detailError, setDetailError] = useState('');
  const pendingDirectClose = useRef<string | null>(null);
  const listRequestId = useRef(0);
  const detailRequestId = useRef(0);
  const detailTab = normalizeDetailTab(searchParams.get('tab'));

  const filters = useMemo(() => filtersFromParams(searchParams), [queryKey]);

  const loadEvents = useCallback(async () => {
    const requestId = ++listRequestId.current;
    setLoading(true);
    setError('');
    try {
      const result = await api.events(filters);
      if (requestId !== listRequestId.current) return;
      setPageData({
        events: result.events,
        total: result.total ?? result.events.length,
        page: result.page ?? filters.page,
        pageSize: result.pageSize ?? filters.pageSize
      });
    } catch (reason) {
      if (requestId !== listRequestId.current) return;
      setError(reason instanceof Error ? reason.message : copy.loadFailed);
    } finally {
      if (requestId === listRequestId.current) setLoading(false);
    }
  }, [copy.loadFailed, filters]);

  useEffect(() => {
    void loadEvents();
    return () => { listRequestId.current += 1; };
  }, [loadEvents]);

  useEffect(() => {
    api.domains().then((result) => setDomains(result.domains)).catch(() => setDomains([]));
  }, []);

  useEffect(() => {
    setDraft(draftFromParams(searchParams));
  }, [queryKey]);

  useEffect(() => {
    const requestId = ++detailRequestId.current;
    if (!eventId) {
      setSelected(null);
      setDetailError('');
      setDetailLoading(false);
      return;
    }
    const id = Number(eventId);
    if (!Number.isInteger(id) || id <= 0) {
      setSelected(null);
      setDetailError(copy.detailNotFound);
      setDetailLoading(false);
      return;
    }
    const preview = pageData?.events.find((event) => event.id === id) || null;
    setSelected(preview);
    setDetailLoading(true);
    setDetailError('');
    api.event(id)
      .then((result) => {
        if (requestId !== detailRequestId.current) return;
        setSelected(result.event);
        if (!result.event) setDetailError(copy.detailNotFound);
      })
      .catch((reason) => {
        if (requestId === detailRequestId.current) {
          setDetailError(reason instanceof Error ? reason.message : copy.detailLoadFailed);
        }
      })
      .finally(() => {
        if (requestId === detailRequestId.current) setDetailLoading(false);
      });
    return () => {
      if (detailRequestId.current === requestId) detailRequestId.current += 1;
    };
  }, [copy.detailLoadFailed, copy.detailNotFound, eventId, pageData?.events]);

  useEffect(() => {
    const target = pendingDirectClose.current;
    if (!target || detailHistoryState(location.state)?.origin === 'direct') return;
    pendingDirectClose.current = null;
    navigate(target, { replace: true });
  }, [location.key, location.state, navigate]);

  function applyFilters() {
    const next = new URLSearchParams();
    if (draft.from) next.set('from', toIso(draft.from));
    if (draft.to) next.set('to', toIso(draft.to));
    if (draft.domainId) next.set('domainId', draft.domainId);
    if (draft.status) next.set('status', draft.status);
    if (draft.recipient.trim()) next.set('recipient', draft.recipient.trim());
    if (draft.q.trim()) next.set('q', draft.q.trim());
    next.set('page', '1');
    next.set('pageSize', String(filters.pageSize));
    setSearchParams(next);
  }

  function clearFilters() {
    const next = new URLSearchParams({ page: '1', pageSize: String(filters.pageSize) });
    setSearchParams(next);
  }

  function changePage(page: number, pageSize: number) {
    const next = new URLSearchParams(searchParams);
    next.set('page', String(pageSize === filters.pageSize ? page : 1));
    next.set('pageSize', String(pageSize));
    setSearchParams(next);
  }

  function openDetail(event: SendEvent) {
    navigate(
      { pathname: `/activity/${event.id}`, search: queryKey ? `?${queryKey}` : '' },
      { state: detailHistoryLocation(`${location.pathname}${location.search}`, 1) }
    );
  }

  function closeDetail() {
    const historyState = detailHistoryState(location.state);
    if (historyState?.origin === 'list') {
      navigate(-historyState.depth);
      return;
    }
    if (historyState?.origin === 'direct') {
      pendingDirectClose.current = historyState.listPath;
      navigate(-historyState.depth);
      return;
    }
    navigate(activityListPath(searchParams), { replace: true });
  }

  function changeDetailTab(tab: DetailTab) {
    const next = new URLSearchParams(searchParams);
    if (tab === 'attempts') next.delete('tab');
    else next.set('tab', tab);
    const historyState = detailHistoryState(location.state);
    const search = next.toString();
    navigate(
      { pathname: location.pathname, search: search ? `?${search}` : '' },
      {
        state: detailHistoryLocation(
          historyState?.listPath || activityListPath(searchParams),
          (historyState?.depth || 0) + 1,
          historyState?.origin || 'direct'
        )
      }
    );
  }

  async function retryDetail() {
    const id = Number(eventId);
    if (!Number.isInteger(id) || id <= 0) return;
    const requestId = ++detailRequestId.current;
    setDetailLoading(true);
    setDetailError('');
    try {
      const result = await api.event(id);
      if (requestId !== detailRequestId.current) return;
      setSelected(result.event);
      if (!result.event) setDetailError(copy.detailNotFound);
    } catch (reason) {
      if (requestId === detailRequestId.current) {
        setDetailError(reason instanceof Error ? reason.message : copy.detailLoadFailed);
      }
    } finally {
      if (requestId === detailRequestId.current) setDetailLoading(false);
    }
  }

  async function copyDiagnostics(event: SendEvent) {
    try {
      await navigator.clipboard.writeText(formatDiagnostics(event));
      message.success(copy.diagnosticsCopied);
    } catch {
      message.error(copy.copyFailed);
    }
  }

  const columns: ColumnsType<SendEvent> = [
    { title: copy.time, dataIndex: 'createdAt', width: 180, render: (value) => formatDateTime(value, locale) },
    { title: copy.recipient, dataIndex: 'recipients', ellipsis: true, render: (value: string[]) => value.join(', ') },
    { title: copy.domain, dataIndex: 'domain', width: 180, render: (value) => value || '-' },
    { title: copy.subject, dataIndex: 'subject', ellipsis: true, render: (value) => displaySubject(value) },
    { title: copy.status, dataIndex: 'status', width: 130, render: (value) => <EventStatus status={value} copy={copy} /> },
    { title: 'Message ID', dataIndex: 'messageId', width: 220, ellipsis: true, render: (_, event) => <Typography.Text code>{messageIdentifier(event)}</Typography.Text> },
    { title: 'Queue ID', dataIndex: 'queueId', width: 150, ellipsis: true, render: (value) => value ? <Typography.Text code>{value}</Typography.Text> : '-' }
  ];

  return (
    <>
      <Space direction="vertical" size={20} className="full-width">
        <PageHeader title={copy.title} subtitle={copy.subtitle} />

        <SectionCard className="logs-toolbar-card">
          <Space direction="vertical" size={12} className="full-width">
            <Space wrap align="end">
              <FilterField label={copy.from}><Input type="datetime-local" aria-label={copy.from} value={draft.from} onChange={(event) => setDraft((current) => ({ ...current, from: event.target.value }))} style={{ minHeight: 44 }} /></FilterField>
              <FilterField label={copy.to}><Input type="datetime-local" aria-label={copy.to} value={draft.to} onChange={(event) => setDraft((current) => ({ ...current, to: event.target.value }))} style={{ minHeight: 44 }} /></FilterField>
              <FilterField label={copy.domain}><Select allowClear showSearch aria-label={copy.domain} placeholder={copy.allDomains} value={draft.domainId} onChange={(value) => setDraft((current) => ({ ...current, domainId: value }))} options={domains.map((domain) => ({ value: String(domain.id), label: domain.domain }))} style={{ width: 190, minHeight: 44 }} /></FilterField>
              <FilterField label={copy.status}><Select allowClear aria-label={copy.status} placeholder={copy.allStatuses} value={draft.status} onChange={(value) => setDraft((current) => ({ ...current, status: value }))} options={statusOptions(copy)} style={{ width: 160, minHeight: 44 }} /></FilterField>
              <FilterField label={copy.recipient}><Input allowClear prefix={<SearchOutlined />} aria-label={copy.recipient} placeholder="user@example.com" value={draft.recipient} onChange={(event) => setDraft((current) => ({ ...current, recipient: event.target.value }))} style={{ width: 220, minHeight: 44 }} /></FilterField>
              <FilterField label={copy.messageSearch}><Input allowClear prefix={<SearchOutlined />} aria-label={copy.messageSearch} placeholder={copy.messageSearchPlaceholder} value={draft.q} onChange={(event) => setDraft((current) => ({ ...current, q: event.target.value }))} onPressEnter={applyFilters} style={{ width: 270, minHeight: 44 }} /></FilterField>
            </Space>
            <Space wrap>
              <Button type="primary" icon={<SearchOutlined />} style={{ minHeight: 44 }} onClick={applyFilters}>{copy.search}</Button>
              <Button icon={<ClearOutlined />} style={{ minHeight: 44 }} onClick={clearFilters}>{copy.clear}</Button>
              <Button icon={<ReloadOutlined />} style={{ minHeight: 44 }} loading={loading} onClick={() => void loadEvents()}>{copy.refresh}</Button>
            </Space>
          </Space>
        </SectionCard>

        {error && !pageData ? (
          <Result status="error" title={copy.loadFailed} subTitle={error} extra={<Button type="primary" onClick={() => void loadEvents()}>{copy.retry}</Button>} />
        ) : (
          <SectionCard title={copy.activityList} extra={<Typography.Text type="secondary">{copy.total(pageData?.total || 0)}</Typography.Text>}>
            {error ? <Alert type="error" showIcon message={error} action={<Button size="small" onClick={() => void loadEvents()}>{copy.retry}</Button>} style={{ marginBottom: 16 }} /> : null}
            {loading && !pageData ? <Skeleton active paragraph={{ rows: 9 }} /> : pageData?.events.length ? screens.md ? (
              <Table
                rowKey="id"
                columns={columns}
                dataSource={pageData.events}
                loading={loading}
                pagination={{ current: pageData.page, pageSize: pageData.pageSize, total: pageData.total, showSizeChanger: true, onChange: changePage }}
                scroll={{ x: 1220 }}
                onRow={(event) => ({
                  onClick: () => openDetail(event),
                  style: { cursor: 'pointer' },
                  'aria-label': `${copy.viewDetail} ${messageIdentifier(event)}`,
                  tabIndex: 0,
                  onKeyDown: (keyboardEvent) => {
                    if (keyboardEvent.target !== keyboardEvent.currentTarget) return;
                    if (keyboardEvent.key === 'Enter' || keyboardEvent.key === ' ') {
                      keyboardEvent.preventDefault();
                      openDetail(event);
                    }
                  }
                })}
                rowClassName={(event) => isFailure(event.status) ? 'activity-row--failed' : event.status === 'deferred' ? 'activity-row--deferred' : ''}
              />
            ) : (
              <Space direction="vertical" size={16} className="full-width">
                <List dataSource={pageData.events} renderItem={(event) => <List.Item><EventCard event={event} copy={copy} locale={locale} onView={() => openDetail(event)} onCopy={() => void copyDiagnostics(event)} /></List.Item>} />
                <Pagination current={pageData.page} pageSize={pageData.pageSize} total={pageData.total} showSizeChanger onChange={changePage} />
              </Space>
            ) : <EmptyState description={hasFilters(searchParams) ? copy.noMatches : copy.noActivity} />}
          </SectionCard>
        )}
      </Space>

      <DeliveryDrawer
        open={Boolean(eventId)}
        event={selected}
        loading={detailLoading}
        error={detailError}
        copy={copy}
        locale={locale}
        activeTab={detailTab}
        onClose={closeDetail}
        onTabChange={changeDetailTab}
        onRetry={() => void retryDetail()}
        onCopy={copyDiagnostics}
      />
    </>
  );
}

function FilterField({ label, children }: { label: string; children: React.ReactNode }) {
  return <Space direction="vertical" size={4}><Typography.Text type="secondary">{label}</Typography.Text>{children}</Space>;
}

function EventCard({ event, copy, locale, onView, onCopy }: { event: SendEvent; copy: typeof zhCopy; locale: string; onView: () => void; onCopy: () => void }) {
  return (
    <Card style={{ width: '100%' }} title={<Space wrap><EventStatus status={event.status} copy={copy} /><Typography.Text ellipsis>{displaySubject(event.subject)}</Typography.Text></Space>} actions={[<Button key="view" type="link" onClick={onView}>{copy.viewDetail}</Button>, ...(isFailure(event.status) ? [<Button key="copy" type="link" icon={<CopyOutlined />} onClick={onCopy}>{copy.copyDiagnostics}</Button>] : [])]}>
      <Descriptions size="small" column={1}>
        <Descriptions.Item label={copy.time}>{formatDateTime(event.createdAt, locale)}</Descriptions.Item>
        <Descriptions.Item label={copy.recipient}><Typography.Text ellipsis>{event.recipients.join(', ')}</Typography.Text></Descriptions.Item>
        <Descriptions.Item label={copy.domain}>{event.domain || '-'}</Descriptions.Item>
      </Descriptions>
    </Card>
  );
}

function DeliveryDrawer({ open, event, loading, error, copy, locale, activeTab, onClose, onTabChange, onRetry, onCopy }: { open: boolean; event: SendEvent | null; loading: boolean; error: string; copy: typeof zhCopy; locale: string; activeTab: DetailTab; onClose: () => void; onTabChange: (tab: DetailTab) => void; onRetry: () => void; onCopy: (event: SendEvent) => Promise<void> }) {
  const screens = Grid.useBreakpoint();
  const timeline = buildEventTimeline(event);
  return (
    <Drawer
      title={event ? <Typography.Text ellipsis style={{ maxWidth: screens.sm ? 480 : 190 }}>{copy.detailTitle} · {messageIdentifier(event)}</Typography.Text> : copy.detailTitle}
      open={open}
      width="min(840px, 100vw)"
      onClose={onClose}
      extra={event ? <Button aria-label={copy.copyDiagnostics} icon={<CopyOutlined />} onClick={() => void onCopy(event)}>{screens.sm ? copy.copyDiagnostics : null}</Button> : null}
    >
      {loading && !event ? <Skeleton active paragraph={{ rows: 12 }} /> : error && !event ? <Result status="error" title={copy.detailLoadFailed} subTitle={error} extra={<Button type="primary" onClick={onRetry}>{copy.retry}</Button>} /> : event ? (
        <Space direction="vertical" size={20} className="full-width">
          {error ? <Alert type="error" showIcon message={error} /> : null}
          <SectionCard title={copy.statusSummary}>
            <Descriptions bordered size="small" column={1}>
              <Descriptions.Item label={copy.status}><EventStatus status={event.status} copy={copy} /></Descriptions.Item>
              <Descriptions.Item label={copy.time}>{formatDateTime(event.createdAt, locale)}</Descriptions.Item>
              <Descriptions.Item label={copy.sender}><BreakableText>{event.sender}</BreakableText></Descriptions.Item>
              <Descriptions.Item label={copy.recipient}><BreakableText>{event.recipients.join(', ')}</BreakableText></Descriptions.Item>
              <Descriptions.Item label={copy.subject}><BreakableText>{displaySubject(event.subject)}</BreakableText></Descriptions.Item>
              <Descriptions.Item label="Message ID"><BreakableCode>{messageIdentifier(event)}</BreakableCode></Descriptions.Item>
              <Descriptions.Item label="Queue ID"><BreakableCode>{event.queueId || '-'}</BreakableCode></Descriptions.Item>
              <Descriptions.Item label={copy.finalResponse}><Space align="start" style={{ maxWidth: '100%' }}><BreakableCode>{event.detail || '-'}</BreakableCode>{event.detail ? <Button type="text" size="small" aria-label={copy.copyDiagnostics} icon={<CopyOutlined />} onClick={() => void onCopy(event)} /> : null}</Space></Descriptions.Item>
            </Descriptions>
          </SectionCard>

          <SectionCard title={copy.eventTimeline}>
            {timeline.length ? <Timeline items={timeline.map((item, index) => ({ key: `${item.stage}-${item.at}-${index}`, color: timelineColor(item.tone), children: <TimelineEntry item={item} copy={copy} locale={locale} /> }))} /> : <EmptyState description={copy.noTimeline} />}
          </SectionCard>

          <SectionCard>
            <Tabs
              activeKey={activeTab}
              onChange={(key) => onTabChange(normalizeDetailTab(key))}
              items={[
                { key: 'attempts', label: copy.deliveryAttempts, children: <DeliveryAttempts attempts={event.deliveryAttempts || []} copy={copy} locale={locale} /> },
                { key: 'tracking', label: copy.engagement, children: <TrackingDetail event={event} copy={copy} locale={locale} /> },
                { key: 'webhooks', label: 'Webhook', children: <WebhookDetail deliveries={event.webhookDeliveries || []} copy={copy} /> },
                { key: 'raw', label: copy.rawLogs, children: <RawLogs entries={event.deliveryLog || []} copy={copy} /> }
              ]}
            />
          </SectionCard>
        </Space>
      ) : null}
    </Drawer>
  );
}

function TimelineEntry({ item, copy, locale }: { item: SendEventTimelineEntry; copy: typeof zhCopy; locale: string }) {
  return <Space direction="vertical" size={2} style={{ maxWidth: '100%' }}><Space wrap><Typography.Text strong>{stageLabel(item.stage, copy)}</Typography.Text>{item.status ? <StatusPill tone={item.tone}>{eventStatus(item.status, copy)}</StatusPill> : null}<Typography.Text type="secondary">{formatDateTime(item.at, locale)}</Typography.Text></Space>{item.recipient ? <BreakableText>To: {item.recipient}</BreakableText> : null}{item.relay ? <BreakableCode>{item.relay}</BreakableCode> : null}{item.response ? <BreakableCode>{item.response}</BreakableCode> : null}</Space>;
}

function DeliveryAttempts({ attempts, copy, locale }: { attempts: DeliveryAttempt[]; copy: typeof zhCopy; locale: string }) {
  if (!attempts.length) return <EmptyState description={copy.noAttempts} />;
  return <Timeline items={attempts.map((attempt, index) => ({ key: `${attempt.at}-${index}`, color: timelineColor(eventTone(attempt.status)), children: <Space direction="vertical" size={2} style={{ maxWidth: '100%' }}><Space wrap><EventStatus status={attempt.status} copy={copy} /><Typography.Text type="secondary">{formatDateTime(attempt.at, locale)}</Typography.Text>{attempt.dsn ? <Typography.Text code>DSN {attempt.dsn}</Typography.Text> : null}</Space>{attempt.recipient ? <BreakableText>To: {attempt.recipient}</BreakableText> : null}{attempt.relay ? <BreakableCode>{attempt.relay}</BreakableCode> : null}{attempt.response ? <BreakableCode>{attempt.response}</BreakableCode> : null}</Space> }))} />;
}

function TrackingDetail({ event, copy, locale }: { event: SendEvent; copy: typeof zhCopy; locale: string }) {
  const screens = Grid.useBreakpoint();
  if (!event.tracking?.enabled) return <Alert type="info" showIcon message={copy.trackingDisabled} />;
  const summary = event.tracking.summary;
  return <Space direction="vertical" size={16} className="full-width"><Descriptions bordered size="small" column={screens.sm ? 2 : 1}><Descriptions.Item label={copy.opens}>{summary?.totalOpens || 0}</Descriptions.Item><Descriptions.Item label={copy.clicks}>{summary?.totalClicks || 0}</Descriptions.Item><Descriptions.Item label={copy.firstOpened}>{formatDateTime(summary?.firstOpenedAt, locale)}</Descriptions.Item><Descriptions.Item label={copy.lastClicked}>{formatDateTime(summary?.lastClickedAt, locale)}</Descriptions.Item><Descriptions.Item label={copy.proxyOpens}>{summary?.proxyOpens || 0}</Descriptions.Item><Descriptions.Item label={copy.scannerEvents}>{summary?.scannerEvents || 0}</Descriptions.Item></Descriptions>{event.tracking.links?.length ? <TrackingLinks links={event.tracking.links} copy={copy} locale={locale} /> : <EmptyState description={copy.noLinks} />}</Space>;
}

function TrackingLinks({ links, copy, locale }: { links: TrackingLink[]; copy: typeof zhCopy; locale: string }) {
  const columns: ColumnsType<TrackingLink> = [{ title: copy.link, dataIndex: 'target', ellipsis: true }, { title: copy.clicks, dataIndex: 'clicks', width: 90 }, { title: copy.lastClicked, dataIndex: 'lastClickedAt', width: 190, render: (value) => formatDateTime(value, locale) }];
  return <Table rowKey="id" size="small" columns={columns} dataSource={links} pagination={false} scroll={{ x: 620 }} />;
}

function WebhookDetail({ deliveries, copy }: { deliveries: WebhookDelivery[]; copy: typeof zhCopy }) {
  const columns: ColumnsType<WebhookDelivery> = [{ title: copy.event, dataIndex: 'eventType', width: 130 }, { title: copy.status, dataIndex: 'status', width: 130, render: (value) => <StatusPill tone={value === 'success' ? 'success' : value === 'dead' ? 'error' : 'warning'}>{value}</StatusPill> }, { title: copy.attempts, dataIndex: 'attemptCount', width: 90 }, { title: 'HTTP', dataIndex: 'responseStatus', width: 90, render: (value) => value ?? '-' }, { title: copy.failureReason, dataIndex: 'error', ellipsis: true, render: (value) => value || '-' }];
  return deliveries.length ? <Table rowKey="id" size="small" columns={columns} dataSource={deliveries} pagination={false} scroll={{ x: 720 }} /> : <EmptyState description={copy.noWebhooks} />;
}

function RawLogs({ entries, copy }: { entries: DeliveryLogEntry[]; copy: typeof zhCopy }) {
  if (!entries.length) return <EmptyState description={copy.noRawLogs} />;
  return <Space direction="vertical" size={12} className="full-width">{entries.map((entry, index) => <Card size="small" key={`${entry.at}-${index}`} title={<Space wrap><Typography.Text strong>{entry.phase}</Typography.Text>{entry.code ? <StatusPill tone={entry.ok === false ? 'error' : 'info'}>{entry.code}</StatusPill> : null}<Typography.Text type="secondary">{formatTime(entry.at)}</Typography.Text></Space>}>{entry.command ? <CodeBlock value={`C: ${entry.command}`} /> : null}{entry.response ? <CodeBlock value={`S: ${entry.response}`} /> : null}{entry.message ? <Typography.Paragraph>{entry.message}</Typography.Paragraph> : null}</Card>)}</Space>;
}

function EventStatus({ status, copy }: { status: string; copy: typeof zhCopy }) {
  return <StatusPill tone={eventTone(status)}>{eventStatus(status, copy)}</StatusPill>;
}

function filtersFromParams(params: URLSearchParams): EventFilters {
  const domainId = Number(params.get('domainId'));
  return {
    page: positiveInteger(params.get('page'), 1),
    pageSize: Math.min(100, positiveInteger(params.get('pageSize'), 20)),
    status: params.get('status') || undefined,
    domainId: Number.isInteger(domainId) && domainId > 0 ? domainId : undefined,
    from: validIso(params.get('from')),
    to: validIso(params.get('to')),
    recipient: params.get('recipient') || undefined,
    q: params.get('q') || undefined
  };
}

function normalizeDetailTab(value: string | null): DetailTab {
  return value === 'tracking' || value === 'webhooks' || value === 'raw' ? value : 'attempts';
}

function draftFromParams(params: URLSearchParams): FilterDraft {
  return { from: toDatetimeLocal(params.get('from')), to: toDatetimeLocal(params.get('to')), domainId: params.get('domainId') || undefined, status: params.get('status') || undefined, recipient: params.get('recipient') || '', q: params.get('q') || '' };
}

function positiveInteger(value: string | null, fallback: number) {
  const parsed = Number(value);
  return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
}

function validIso(value: string | null) {
  if (!value || Number.isNaN(Date.parse(value))) return undefined;
  return value;
}

function toIso(value: string) {
  const date = new Date(value);
  return Number.isNaN(date.getTime()) ? '' : date.toISOString();
}

function toDatetimeLocal(value: string | null) {
  if (!value || Number.isNaN(Date.parse(value))) return '';
  const date = new Date(value);
  const offset = date.getTimezoneOffset() * 60_000;
  return new Date(date.getTime() - offset).toISOString().slice(0, 16);
}

function hasFilters(params: URLSearchParams) {
  return ['from', 'to', 'domainId', 'status', 'recipient', 'q'].some((key) => params.has(key));
}

function statusOptions(copy: typeof zhCopy) {
  return ['queued', 'sent', 'deferred', 'bounced', 'failed'].map((value) => ({ value, label: eventStatus(value, copy) }));
}

function isFailure(status: string) {
  return status === 'failed' || status === 'bounced';
}

function eventTone(status: string): 'success' | 'warning' | 'error' | 'info' | 'neutral' {
  if (status === 'sent' || status === 'delivered' || status === 'success') return 'success';
  if (status === 'queued' || status === 'processing') return 'info';
  if (status === 'deferred' || status === 'pending') return 'warning';
  if (status === 'failed' || status === 'bounced' || status === 'dead') return 'error';
  return 'neutral';
}

function eventStatus(status: string, copy: typeof zhCopy) {
  return ({ queued: copy.queued, sent: copy.sent, delivered: copy.delivered, deferred: copy.deferred, bounced: copy.bounced, failed: copy.failed, pending: copy.pending } as Record<string, string>)[status] || status;
}

function stageLabel(stage: string, copy: typeof zhCopy) {
  return ({ submitted: copy.submitted, accepted: copy.accepted, delivered: copy.delivered, pending: copy.pending, failed: copy.failed, opened: copy.opened, clicked: copy.clicked, webhook: 'Webhook' } as Record<string, string>)[stage] || stage;
}

function timelineColor(tone: ReturnType<typeof eventTone> | SendEventTimelineEntry['tone']) {
  return ({ success: 'green', warning: 'orange', error: 'red', info: 'blue', neutral: 'gray' } as const)[tone];
}

function formatTime(value?: string | null) {
  return formatDateTime(value, undefined);
}

function formatDateTime(value?: string | null, locale?: string) {
  if (!value) return '-';
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return '-';
  return new Intl.DateTimeFormat(locale, {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false
  }).format(date);
}

function displaySubject(value?: string | null) {
  return decodeMimeHeader(value || '') || '-';
}

function decodeMimeHeader(value: string) {
  const expression = /=\?([^?]+)\?([bq])\?([^?]+)\?=/gi;
  let output = '';
  let cursor = 0;
  let previousWasEncoded = false;
  for (const match of value.matchAll(expression)) {
    const between = value.slice(cursor, match.index);
    const decoded = decodeEncodedWord(match[1], match[2], match[3]);
    if (decoded == null) {
      output += between + match[0];
      previousWasEncoded = false;
    } else {
      output += previousWasEncoded && /^[\t\r\n ]+$/.test(between) ? '' : between;
      output += decoded;
      previousWasEncoded = true;
    }
    cursor = (match.index || 0) + match[0].length;
  }
  return output + value.slice(cursor);
}

function decodeEncodedWord(charset: string, encoding: string, encoded: string) {
  try {
    const bytes = encoding.toLowerCase() === 'b'
      ? decodeBase64(encoded)
      : decodeQuotedPrintable(encoded);
    if (!bytes) return null;
    const normalized = charset.trim().toLowerCase() === 'utf8' ? 'utf-8' : charset.trim().toLowerCase();
    return new TextDecoder(normalized, { fatal: true }).decode(bytes);
  } catch {
    return null;
  }
}

function decodeBase64(value: string) {
  if (!/^[a-z0-9+/]+={0,2}$/i.test(value) || value.length % 4 === 1) return null;
  const unpadded = value.replace(/=+$/, '');
  const padded = unpadded.padEnd(Math.ceil(unpadded.length / 4) * 4, '=');
  try {
    return Uint8Array.from(atob(padded), (character) => character.charCodeAt(0));
  } catch {
    return null;
  }
}

function decodeQuotedPrintable(value: string) {
  const source = value.replace(/_/g, ' ');
  const bytes: number[] = [];
  for (let index = 0; index < source.length; index += 1) {
    if (source[index] === '=' && /^[0-9a-f]{2}$/i.test(source.slice(index + 1, index + 3))) {
      bytes.push(Number.parseInt(source.slice(index + 1, index + 3), 16));
      index += 2;
    } else {
      bytes.push(source.charCodeAt(index));
    }
  }
  return Uint8Array.from(bytes);
}

function BreakableCode({ children }: { children: React.ReactNode }) {
  return <Typography.Text code style={{ overflowWrap: 'anywhere', wordBreak: 'break-word', maxWidth: '100%' }}>{children}</Typography.Text>;
}

function BreakableText({ children }: { children: React.ReactNode }) {
  return <Typography.Text style={{ overflowWrap: 'anywhere', wordBreak: 'break-word', maxWidth: '100%' }}>{children}</Typography.Text>;
}

function formatDiagnostics(event: SendEvent) {
  const attempts = (event.deliveryAttempts || []).map((attempt) => `${attempt.at || '-'} ${attempt.status} ${attempt.dsn || ''} ${attempt.recipient || ''} ${attempt.response || ''}`.trim());
  const logs = (event.deliveryLog || []).map((entry) => `${entry.at || '-'} [${entry.phase}] ${entry.command || entry.response || entry.message || ''}`.trim());
  return [`Message ID: ${messageIdentifier(event)}`, `Queue ID: ${event.queueId || '-'}`, `Status: ${event.status}`, `Created: ${event.createdAt}`, `Sender: ${event.sender}`, `Recipients: ${event.recipients.join(', ')}`, `Response: ${event.detail || '-'}`, '', 'Delivery attempts:', ...(attempts.length ? attempts : ['-']), '', 'Raw log:', ...(logs.length ? logs : ['-'])].join('\n');
}

function messageIdentifier(event: SendEvent) {
  return event.messageId || `mh-${event.id}`;
}

function activityListPath(searchParams: URLSearchParams) {
  const next = new URLSearchParams(searchParams);
  next.delete('tab');
  const search = next.toString();
  return `/activity${search ? `?${search}` : ''}`;
}

const zhCopy = {
  title: '发送活动', subtitle: '按服务端数据定位发送、延迟、退信和失败事件。', loadFailed: '发送活动加载失败', retry: '重试', from: '开始时间', to: '结束时间', domain: '发信域名', allDomains: '全部域名', status: '状态', allStatuses: '全部状态', recipient: '收件人', messageSearch: '消息检索', messageSearchPlaceholder: '主题 / Message ID / Queue ID', search: '查询', clear: '清除', refresh: '刷新', activityList: '活动列表', total: (count: number) => `共 ${count} 条`, noMatches: '没有符合当前条件的发送活动', noActivity: '尚无发送活动',
  time: '时间', subject: '主题', failureReason: '投递响应', copyDiagnostics: '复制诊断信息', viewDetail: '查看发送详情', detailTitle: '发送详情', detailLoadFailed: '发送详情加载失败', detailNotFound: '未找到该发送记录，或当前账户没有访问权限。', diagnosticsCopied: '诊断信息已复制', copyFailed: '复制失败', statusSummary: '状态摘要', sender: '发件人', finalResponse: '最终响应', eventTimeline: '事件时间线', noTimeline: '暂无可用事件时间线',
  deliveryAttempts: '投递尝试', noAttempts: '暂无最终投递回执，邮件可能仍在队列中。', engagement: '互动跟踪', trackingDisabled: '这封邮件发送时未启用打开或点击追踪。', opens: '打开', clicks: '点击', firstOpened: '首次打开', lastClicked: '最近点击', proxyOpens: '代理打开', scannerEvents: '扫描器事件', noLinks: '暂无链接点击数据', link: '链接', event: '事件', attempts: '尝试次数', noWebhooks: '暂无关联 Webhook 投递', rawLogs: '原始日志', noRawLogs: '暂无结构化原始日志，可能是历史发送记录。',
  queued: '已入队', sent: '已发送', delivered: '已送达', deferred: '已延迟', bounced: '已退信', failed: '失败', pending: '等待投递', submitted: '已提交', accepted: '队列已接收', opened: '已打开', clicked: '已点击'
};

const enCopy: typeof zhCopy = {
  title: 'Sending activity', subtitle: 'Use server-side data to investigate sends, delays, bounces, and failures.', loadFailed: 'Unable to load sending activity', retry: 'Retry', from: 'From', to: 'To', domain: 'Sending domain', allDomains: 'All domains', status: 'Status', allStatuses: 'All statuses', recipient: 'Recipient', messageSearch: 'Message search', messageSearchPlaceholder: 'Subject / Message ID / Queue ID', search: 'Search', clear: 'Clear', refresh: 'Refresh', activityList: 'Activity', total: (count: number) => `${count} events`, noMatches: 'No sending activity matches these filters', noActivity: 'No sending activity yet',
  time: 'Time', subject: 'Subject', failureReason: 'Delivery response', copyDiagnostics: 'Copy diagnostics', viewDetail: 'View sending details', detailTitle: 'Sending details', detailLoadFailed: 'Unable to load sending details', detailNotFound: 'The sending event was not found or is not available to this account.', diagnosticsCopied: 'Diagnostics copied', copyFailed: 'Unable to copy', statusSummary: 'Status summary', sender: 'Sender', finalResponse: 'Final response', eventTimeline: 'Event timeline', noTimeline: 'No event timeline available',
  deliveryAttempts: 'Delivery attempts', noAttempts: 'No final delivery receipt yet. The message may still be queued.', engagement: 'Engagement', trackingDisabled: 'Open and click tracking was not enabled for this message.', opens: 'Opens', clicks: 'Clicks', firstOpened: 'First opened', lastClicked: 'Last clicked', proxyOpens: 'Proxy opens', scannerEvents: 'Scanner events', noLinks: 'No link click data', link: 'Link', event: 'Event', attempts: 'Attempts', noWebhooks: 'No related webhook delivery', rawLogs: 'Raw logs', noRawLogs: 'No structured raw log is available. This may be a historical event.',
  queued: 'Queued', sent: 'Sent', delivered: 'Delivered', deferred: 'Deferred', bounced: 'Bounced', failed: 'Failed', pending: 'Pending', submitted: 'Submitted', accepted: 'Accepted by queue', opened: 'Opened', clicked: 'Clicked'
};
