import { useEffect, useRef, useState } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { Mail, Reply, Paperclip } from 'lucide-react';
import { FileViewerProvider, FileViewerHeader, FileViewerBody } from 'officerdev';
import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog';
import { useClient } from 'hooks/useClient';
import type { EmailMessage, EmailThread } from 'types';
import { useComposer, replyDraft } from './Compose';
import { useSelectedEmailId } from './shared';

type OpenAttachment = {
  filePath: string;
  fileName: string;
  root: string;
};

const senderName = (from: string) => from.replace(/\s*<[^>]+>$/, '').trim() || from;

const HtmlBody = ({ html }: { html: string }) => {
  const iframeRef = useRef<HTMLIFrameElement>(null);

  useEffect(() => {
    const iframe = iframeRef.current;
    if (!iframe) return;
    const doc = iframe.contentDocument;
    if (!doc) return;
    doc.open();
    doc.write(`
      <!DOCTYPE html>
      <html>
        <head>
          <style>
            body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-size: 14px; margin: 0; padding: 16px; color: #1a1a1a; background: #ffffff; }
            a { color: #1a73e8; }
            img { max-width: 100%; height: auto; }
          </style>
        </head>
        <body>${html}</body>
      </html>
    `);
    doc.close();
    // Auto-size to content so each message sits at its natural height inside the stacked thread.
    const resize = () => {
      if (doc.body) iframe.style.height = `${doc.body.scrollHeight + 8}px`;
    };
    resize();
    doc.querySelectorAll('img').forEach((img) => img.addEventListener('load', resize));
    const t = setTimeout(resize, 300);
    return () => clearTimeout(t);
  }, [html]);

  return <iframe ref={iframeRef} className="w-full border-0" sandbox="allow-same-origin" title="Email body" />;
};

type MessagePanelProps = {
  message: EmailMessage;
  open: boolean;
  onToggle: () => void;
  onReply: () => void;
  onOpenAttachment: (index: number) => void;
};

const MessagePanel = ({ message, open, onToggle, onReply, onOpenAttachment }: MessagePanelProps) => {
  if (!open) {
    return (
      <button
        onClick={onToggle}
        className="flex w-full items-center gap-2 px-4 py-2.5 text-left hover:bg-accent/40 cursor-pointer"
      >
        <span className={`shrink-0 text-sm ${message.read ? 'opacity-70' : 'font-semibold'}`}>
          {senderName(message.from)}
        </span>
        <span className="min-w-0 flex-1 truncate text-xs opacity-50">{message.snippet}</span>
        {!!message.attachmentCount && <Paperclip className="h-3 w-3 shrink-0 opacity-40" />}
        <span className="shrink-0 text-xs opacity-50">{new Date(message.date).toLocaleDateString()}</span>
      </button>
    );
  }

  return (
    <div className="flex flex-col">
      <div className="flex items-start justify-between gap-3 px-4 py-2.5">
        <button onClick={onToggle} className="min-w-0 flex-1 text-left cursor-pointer">
          <div className="flex flex-col gap-0.5 text-sm opacity-80">
            <div>
              <span className="font-medium">{message.from}</span>
            </div>
            <div className="text-xs opacity-70">
              <span className="font-medium">To:</span> {message.to}
            </div>
            {message.cc && (
              <div className="text-xs opacity-70">
                <span className="font-medium">Cc:</span> {message.cc}
              </div>
            )}
            <div className="text-xs opacity-60">{new Date(message.date).toLocaleString()}</div>
          </div>
        </button>
        <button
          onClick={onReply}
          className="shrink-0 flex items-center gap-1 rounded-md border px-2.5 py-1 text-xs hover:bg-accent cursor-pointer"
          title="Reply"
        >
          <Reply className="h-3.5 w-3.5" /> Reply
        </button>
      </div>

      {message.attachments.length > 0 && (
        <div className="flex flex-wrap gap-1.5 px-4 pb-2">
          {message.attachments.map((att, i) => (
            <button
              key={i}
              className="cursor-pointer rounded bg-accent px-2 py-0.5 text-xs hover:bg-accent/80"
              onClick={() => onOpenAttachment(i)}
            >
              {att.filename} ({Math.round(att.size / 1024)}KB)
            </button>
          ))}
        </div>
      )}

      {message.html ? (
        <HtmlBody html={message.html} />
      ) : (
        <pre className="whitespace-pre-wrap px-4 pb-4 text-sm">{message.text}</pre>
      )}
    </div>
  );
};

export const EmailReader = () => {
  const client = useClient();
  const queryClient = useQueryClient();
  const [, openCompose] = useComposer();
  // Reads the URL itself rather than being told by the list — the two panels never talk.
  const selectedId = useSelectedEmailId();
  const [openAttachment, setOpenAttachment] = useState<OpenAttachment | null>(null);
  const [expanded, setExpanded] = useState<Set<string>>(new Set());

  const { data: thread, isLoading } = useQuery({
    queryKey: ['email-thread', selectedId],
    queryFn: () => client.get<EmailThread>(`/email/thread/${selectedId}`),
    enabled: !!selectedId,
  });

  // Whenever the thread changes, expand just the latest message (Gmail-style).
  useEffect(() => {
    const messages = thread?.messages;
    if (messages?.length) setExpanded(new Set([messages[messages.length - 1]!.id]));
  }, [thread?.id, thread?.messages.length]);

  // Mark the whole conversation as read when opened.
  useEffect(() => {
    if (!thread || !selectedId || !thread.messages.some((m: EmailMessage) => !m.read)) return;
    client
      .patch(`/email/thread/${selectedId}/read`)
      .then(() => queryClient.invalidateQueries({ queryKey: ['email-messages'] }))
      .catch(() => {});
  }, [thread?.id]);

  const extractAttachment = async (messageId: string, index: number) => {
    const result = await client.post<OpenAttachment>(`/email/messages/${messageId}/attachments/${index}/extract`);
    setOpenAttachment(result);
  };

  const toggle = (id: string) =>
    setExpanded((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });

  if (!selectedId) {
    return (
      <div className="flex h-full flex-col items-center justify-center gap-2 text-sm opacity-50">
        <Mail className="h-10 w-10" />
        Select an email to read
      </div>
    );
  }

  if (isLoading) {
    return <div className="flex h-full items-center justify-center text-sm opacity-50">Loading...</div>;
  }

  if (!thread || thread.messages.length === 0) return null;

  const latest = thread.messages[thread.messages.length - 1]!;

  return (
    <div className="flex h-full flex-col overflow-hidden">
      <div className="flex items-start justify-between gap-3 border-b px-4 py-3">
        <h2 className="text-lg font-semibold">{thread.subject}</h2>
        <button
          onClick={() => openCompose(replyDraft(latest))}
          className="shrink-0 flex items-center gap-1 rounded-md border px-2.5 py-1 text-xs hover:bg-accent cursor-pointer"
          title="Reply"
        >
          <Reply className="h-3.5 w-3.5" /> Reply
        </button>
      </div>

      <div className="flex-1 divide-y divide-white/10 overflow-auto">
        {thread.messages.map((m: EmailMessage) => (
          <MessagePanel
            key={m.id}
            message={m}
            open={expanded.has(m.id)}
            onToggle={() => toggle(m.id)}
            onReply={() => openCompose(replyDraft(m))}
            onOpenAttachment={(index) => extractAttachment(m.id, index)}
          />
        ))}
      </div>

      <Dialog open={!!openAttachment} onOpenChange={(open) => !open && setOpenAttachment(null)}>
        <DialogContent className="flex h-[80vh] max-w-4xl flex-col gap-0 p-0">
          <DialogTitle className="sr-only">{openAttachment?.fileName}</DialogTitle>
          {openAttachment && (
            <FileViewerProvider
              filePath={openAttachment.filePath}
              fileName={openAttachment.fileName}
              root={openAttachment.root}
            >
              <div className="flex shrink-0 items-center gap-2 border-b px-4 pr-12 py-1.5">
                <FileViewerHeader />
              </div>
              <div className="min-h-0 flex-1">
                <FileViewerBody />
              </div>
            </FileViewerProvider>
          )}
        </DialogContent>
      </Dialog>
    </div>
  );
};
