'use client';

import { Text } from '@tale/ui/text';
import { Clock, AlertCircle, Paperclip, Download, Loader2 } from 'lucide-react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';

import { EmailPreview } from '@/app/components/ui/data-display/email-preview';
import { Image } from '@/app/components/ui/data-display/image';
import {
  formatFileSize,
  middleEllipsis,
} from '@/app/features/chat/components/message-bubble/file-displays';
import { useFormatDate } from '@/app/hooks/use-format-date';
import { useT } from '@/lib/i18n/client';
import { cn } from '@/lib/utils/cn';

import type { Message as MessageType } from '../types';

type Attachment = NonNullable<MessageType['attachments']>[number];

interface MessageProps {
  message: MessageType;
  onDownloadAttachments?: (messageId: string) => void;
}

function getDeliveryIcon(status: string) {
  switch (status) {
    case 'queued':
      return <Clock className="size-3" />;
    case 'failed':
      return <AlertCircle className="size-3" />;
    default:
      return null;
  }
}

function getFileIcon(contentType: string, filename: string) {
  if (contentType.startsWith('image/')) return '🖼️';
  if (contentType === 'application/pdf') return '📄';
  if (
    contentType.includes('word') ||
    filename.endsWith('.doc') ||
    filename.endsWith('.docx')
  )
    return '📝';
  if (
    contentType.includes('spreadsheet') ||
    contentType.includes('excel') ||
    filename.endsWith('.xls') ||
    filename.endsWith('.xlsx') ||
    filename.endsWith('.csv')
  )
    return '📊';
  if (
    contentType.includes('presentation') ||
    contentType.includes('powerpoint') ||
    filename.endsWith('.ppt') ||
    filename.endsWith('.pptx')
  )
    return '📊';
  if (contentType.startsWith('text/')) return '📄';
  return '📎';
}

interface AttachmentCardProps {
  attachment: {
    id: string;
    filename: string;
    contentType: string;
    size: number;
    storageId?: string;
    url?: string;
  };
  isDownloading?: boolean;
  onDownload?: () => void;
}

function AttachmentCard({
  attachment,
  isDownloading,
  onDownload,
}: AttachmentCardProps) {
  const { t } = useT('conversations');

  const icon = getFileIcon(attachment.contentType, attachment.filename);
  const hasUrl = !!attachment.url;

  return (
    <div className="bg-background flex items-center gap-2 rounded-lg border p-2">
      <div className="flex size-8 shrink-0 items-center justify-center rounded-lg bg-gray-100">
        <span className="text-sm">{icon}</span>
      </div>
      <div className="min-w-0 flex-1">
        <Text variant="label-sm" title={attachment.filename}>
          {middleEllipsis(attachment.filename, 28)}
        </Text>
        <Text variant="caption" className="text-[10px]">
          {isDownloading
            ? t('attachment.downloading')
            : formatFileSize(attachment.size)}
        </Text>
      </div>
      {isDownloading ? (
        <div className="text-muted-foreground flex size-6 shrink-0 items-center justify-center">
          <Loader2 className="size-3.5 animate-spin" />
        </div>
      ) : hasUrl || onDownload ? (
        <button
          type="button"
          onClick={() => {
            if (attachment.url) {
              const a = document.createElement('a');
              a.href = attachment.url;
              a.download = attachment.filename;
              a.click();
            } else {
              onDownload?.();
            }
          }}
          className="text-muted-foreground hover:text-foreground flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-md hover:bg-gray-100"
          aria-label={`${t('attachment.download')} ${attachment.filename}`}
        >
          <Download className="size-3.5" />
        </button>
      ) : null}
    </div>
  );
}

export function Message({ message, onDownloadAttachments }: MessageProps) {
  const { formatDate } = useFormatDate();
  const { t } = useT('conversations');
  const [downloadingMessageId, setDownloadingMessageId] = useState<
    string | null
  >(null);

  // Track which attachment filenames had no URL when download was triggered
  const pendingDownloadFiles = useRef(new Set<string>());

  const handleDownload = useCallback(
    (messageId: string) => {
      if (!onDownloadAttachments || downloadingMessageId) return;
      // Record filenames that don't have URLs yet
      pendingDownloadFiles.current.clear();
      for (const att of message.attachments ?? []) {
        if (!att.url) {
          pendingDownloadFiles.current.add(att.filename);
        }
      }
      setDownloadingMessageId(messageId);
      onDownloadAttachments(messageId);
    },
    [onDownloadAttachments, downloadingMessageId, message.attachments],
  );

  // When URLs appear on previously-pending attachments, auto-trigger browser download
  useEffect(() => {
    if (!downloadingMessageId || pendingDownloadFiles.current.size === 0)
      return;

    const readyAttachments = (message.attachments ?? []).filter(
      (att: Attachment) =>
        att.url && pendingDownloadFiles.current.has(att.filename),
    );

    if (readyAttachments.length === 0) return;

    // All pending files now have URLs — trigger downloads and clear state
    for (const att of readyAttachments) {
      pendingDownloadFiles.current.delete(att.filename);
      if (att.url) {
        const a = document.createElement('a');
        a.href = att.url;
        a.download = att.filename;
        a.click();
      }
    }

    if (pendingDownloadFiles.current.size === 0) {
      setDownloadingMessageId(null);
    }
  }, [downloadingMessageId, message.attachments]);

  const isDownloading = downloadingMessageId === message.id;

  // Build CID→URL map for inline images that have been downloaded
  const cidMap = useMemo(() => {
    const normalizeCid = (cid: string) => cid.trim().replace(/^<|>$/g, '');
    const map: Record<string, string> = {};
    for (const att of message.attachments ?? []) {
      if (att.contentId && att.url) {
        map[normalizeCid(att.contentId)] = att.url;
      }
    }
    return map;
  }, [message.attachments]);

  // Filter out resolved inline attachments from the displayed attachment list.
  // Unresolved inline attachments (contentId but no url) remain visible as a
  // fallback so users can still see and manually download them if auto-download fails.
  const displayAttachments = useMemo(
    () =>
      (message.attachments ?? []).filter(
        (att: Attachment) => !(att.contentId && att.url),
      ),
    [message.attachments],
  );

  // Auto-trigger download for inline images that don't have URLs yet.
  // This handles two cases:
  // 1. Attachments with contentId metadata but no URL (new syncs)
  // 2. HTML with cid: refs but attachments lack contentId (legacy syncs) —
  //    downloading populates contentId from the connector's return data
  const inlineDownloadTriggered = useRef(false);
  useEffect(() => {
    if (inlineDownloadTriggered.current || !onDownloadAttachments) return;
    const attachments = message.attachments ?? [];
    const hasUnresolvedInline = attachments.some(
      (att: Attachment) => att.contentId && !att.url,
    );
    const hasCidInHtml =
      !hasUnresolvedInline &&
      /src=["']cid:/i.test(message.content) &&
      attachments.some((att: Attachment) => !att.url && !att.contentId);
    if (hasUnresolvedInline || hasCidInHtml) {
      inlineDownloadTriggered.current = true;
      onDownloadAttachments(message.id);
    }
  }, [message.attachments, message.content, message.id, onDownloadAttachments]);

  return (
    <div className="flex flex-col">
      <div
        className={cn(
          'flex',
          message.isCustomer ? 'justify-start' : 'justify-end',
        )}
      >
        <div className="relative">
          <div
            className={cn(
              'max-w-[40rem] relative overflow-x-auto rounded-2xl shadow-sm mb-2',
              message.isCustomer
                ? 'bg-card text-foreground'
                : 'bg-muted text-foreground',
            )}
          >
            {(() => {
              if (
                message.attachment &&
                typeof message.attachment === 'object' &&
                message.attachment !== null &&
                'url' in message.attachment
              ) {
                const attachment = message.attachment as {
                  url: string;
                  type?: string;
                  alt?: string;
                };
                return (
                  <div className="mb-3">
                    <Image
                      src={attachment.url}
                      alt={
                        attachment.type === 'image'
                          ? attachment.alt || t('fallbackImageAttachment')
                          : t('fallbackAttachment')
                      }
                      width={460}
                      height={300}
                      className="h-auto w-full rounded-lg"
                    />
                  </div>
                );
              }
              return null;
            })()}
            <Text as="div" variant="body-sm" className="leading-5">
              <EmailPreview html={message.content} cidMap={cidMap} />
            </Text>
            {displayAttachments.length > 0 && (
              <div className="flex flex-col gap-1.5 px-3 pb-3">
                <div className="flex items-center gap-1">
                  <Paperclip className="text-muted-foreground size-3" />
                  <Text as="span" variant="caption" className="text-[10px]">
                    {t('attachment.attachments', {
                      count: displayAttachments.length,
                    })}
                  </Text>
                </div>
                <div className="flex flex-col gap-1">
                  {displayAttachments.map((att: Attachment) => (
                    <AttachmentCard
                      key={att.id}
                      attachment={att}
                      isDownloading={isDownloading && !att.url}
                      onDownload={
                        !att.url && onDownloadAttachments
                          ? () => handleDownload(message.id)
                          : undefined
                      }
                    />
                  ))}
                </div>
              </div>
            )}
          </div>
          <Text
            as="div"
            variant="caption"
            className={cn(
              'flex items-center gap-1.5 justify-end text-nowrap',
              message.isCustomer
                ? 'text-left'
                : 'text-muted-foreground/70 text-right mb-4',
            )}
          >
            {formatDate(message.timestamp, 'time')}
            {!message.isCustomer && message.status && (
              <span className="inline-flex items-center">
                {getDeliveryIcon(message.status)}
              </span>
            )}
          </Text>
        </div>
      </div>
    </div>
  );
}
