import { Archive, Download, FileText, FileUp, Flag, MailOpen, Paperclip, PenLine, Search, Send, X } from "lucide-react";
import { useMemo, useRef, useState } from "react";
import type { MailAttachment, MailMessage, QOfficeState } from "../../types";
import { downloadBlobFile } from "../../utils/download";
import { attachmentToBlob, createMailAttachmentFromFile, exportEmlBlob, importMailFile } from "../../io/outlookMail";
import { replaceFileExtension } from "../../io/fileHelpers";
import { isDesktopOfficeBridgeAvailable, openDesktopOfficeFile, saveDesktopOfficeFile } from "../../io/desktopOfficeFiles";
import { exportPdfOrPrint } from "../../io/pdfExport";
import { useQOfficeCommand } from "../../hooks/useQOfficeCommand";

interface QOutlookProps {
  mail: QOfficeState["mail"];
  onChange: (updater: (mail: QOfficeState["mail"]) => QOfficeState["mail"]) => void;
  onFolderChange: (folder: MailMessage["folder"]) => void;
}

const folders: Array<{ id: MailMessage["folder"]; label: string }> = [
  { id: "inbox", label: "Входящие" },
  { id: "sent", label: "Отправленные" },
  { id: "drafts", label: "Черновики" },
  { id: "archive", label: "Архив" }
];

function formatBytes(bytes: number): string {
  if (!Number.isFinite(bytes) || bytes <= 0) {
    return "0 Б";
  }

  const units = ["Б", "КБ", "МБ", "ГБ"];
  let value = bytes;
  let unitIndex = 0;

  while (value >= 1024 && unitIndex < units.length - 1) {
    value /= 1024;
    unitIndex += 1;
  }

  return `${Number.isInteger(value) ? value : value.toFixed(1)} ${units[unitIndex]}`;
}

export function QOutlook({ mail, onChange, onFolderChange }: QOutlookProps) {
  const fileInputRef = useRef<HTMLInputElement>(null);
  const draftAttachmentInputRef = useRef<HTMLInputElement>(null);
  const [query, setQuery] = useState("");
  const [draft, setDraft] = useState<{ to: string; subject: string; body: string; attachments: MailAttachment[] }>({
    to: "",
    subject: "",
    body: "",
    attachments: []
  });
  const activeMessage = mail.messages.find((message) => message.id === mail.activeMessageId) ?? mail.messages[0];

  const visibleMessages = useMemo(() => {
    const normalizedQuery = query.trim().toLowerCase();
    return mail.messages.filter((message) => {
      const inFolder = message.folder === mail.activeFolder;
      const matchesQuery =
        !normalizedQuery ||
        [message.from, message.to, message.subject, message.body, ...(message.attachments ?? []).map((attachment) => attachment.fileName)].some((field) =>
          field.toLowerCase().includes(normalizedQuery)
        );
      return inFolder && matchesQuery;
    });
  }, [mail.activeFolder, mail.messages, query]);

  function updateMessage(id: string, patch: Partial<MailMessage>) {
    onChange((current) => ({
      ...current,
      messages: current.messages.map((message) => (message.id === id ? { ...message, ...patch } : message))
    }));
  }

  function sendDraft() {
    if (!draft.to.trim() || !draft.subject.trim()) {
      return;
    }

    const id = `mail-${Date.now()}`;
    const message: MailMessage = {
      id,
      folder: "sent",
      from: "product@qoffice.local",
      to: draft.to.trim(),
      subject: draft.subject.trim(),
      body: draft.body.trim(),
      time: new Date().toLocaleTimeString("ru-RU", { hour: "2-digit", minute: "2-digit" }),
      read: true,
      flagged: false,
      attachments: draft.attachments
    };

    onChange((current) => ({
      ...current,
      activeFolder: "sent",
      activeMessageId: id,
      messages: [message, ...current.messages]
    }));
    setDraft({ to: "", subject: "", body: "", attachments: [] });
  }

  async function openMailFile(file: File | undefined) {
    if (!file) {
      return;
    }

    try {
      const imported = await importMailFile(file);
      onChange((current) => ({
        ...current,
        activeFolder: "inbox",
        activeMessageId: imported.id,
        messages: [imported, ...current.messages]
      }));
    } catch (error) {
      window.alert(error instanceof Error ? error.message : "Не удалось открыть письмо.");
    } finally {
      if (fileInputRef.current) {
        fileInputRef.current.value = "";
      }
    }
  }

  async function saveEml(message: MailMessage) {
    try {
      const blob = exportEmlBlob(message);
      const fileName = replaceFileExtension(message.subject || "Письмо", ".eml");
      if (isDesktopOfficeBridgeAvailable()) {
        await saveDesktopOfficeFile("eml", fileName, blob);
        return;
      }

      downloadBlobFile(fileName, blob);
    } catch (error) {
      window.alert(error instanceof Error ? error.message : "Не удалось сохранить EML.");
    }
  }

  async function addDraftAttachments(files: FileList | null) {
    if (!files || files.length === 0) {
      return;
    }

    try {
      const attachments = await Promise.all(Array.from(files).map((file) => createMailAttachmentFromFile(file)));
      setDraft((current) => ({ ...current, attachments: [...current.attachments, ...attachments] }));
    } catch (error) {
      window.alert(error instanceof Error ? error.message : "Не удалось добавить вложение.");
    } finally {
      if (draftAttachmentInputRef.current) {
        draftAttachmentInputRef.current.value = "";
      }
    }
  }

  function removeDraftAttachment(id: string) {
    setDraft((current) => ({
      ...current,
      attachments: current.attachments.filter((attachment) => attachment.id !== id)
    }));
  }

  function downloadAttachment(attachment: MailAttachment) {
    downloadBlobFile(attachment.fileName, attachmentToBlob(attachment));
  }

  async function chooseMailFile() {
    if (isDesktopOfficeBridgeAvailable()) {
      const file = await openDesktopOfficeFile("mail");
      await openMailFile(file ?? undefined);
      return;
    }

    fileInputRef.current?.click();
  }

  async function exportPdf() {
    try {
      await exportPdfOrPrint(activeMessage?.subject || "Письмо QOutlook");
    } catch (error) {
      window.alert(error instanceof Error ? error.message : "Не удалось экспортировать PDF.");
    }
  }

  useQOfficeCommand({
    open: chooseMailFile,
    save: () => {
      if (activeMessage) {
        void saveEml(activeMessage);
      }
    },
    "export-pdf": exportPdf,
    print: () => window.print()
  });

  const activeAttachments = activeMessage?.attachments ?? [];

  return (
    <div className="mail-layout">
      <aside className="mail-folders" aria-label="Папки почты">
        <input
          ref={fileInputRef}
          className="hidden-file-input"
          type="file"
          accept=".eml,.msg,message/rfc822,application/vnd.ms-outlook"
          onChange={(event) => void openMailFile(event.target.files?.[0])}
          aria-label="Открыть EML или MSG"
        />
        <button className="wide-command compose-command" type="button">
          <PenLine size={16} />
          Написать
        </button>
        <button className="wide-command" type="button" onClick={() => void chooseMailFile()}>
          <FileUp size={16} />
          Открыть EML/MSG
        </button>
        {folders.map((folder) => {
          const count = mail.messages.filter((message) => message.folder === folder.id).length;
          return (
            <button
              type="button"
              key={folder.id}
              className={mail.activeFolder === folder.id ? "is-active" : ""}
              onClick={() => onFolderChange(folder.id)}
            >
              <span>{folder.label}</span>
              <span>{count}</span>
            </button>
          );
        })}
      </aside>

      <section className="message-list-panel" aria-label="Список писем">
        <label className="mail-search">
          <Search size={16} />
          <input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Поиск писем" />
        </label>
        <div className="message-list">
          {visibleMessages.map((message) => {
            const attachmentCount = message.attachments?.length ?? 0;
            return (
              <button
                type="button"
                key={message.id}
                className={`message-row ${message.id === activeMessage?.id ? "is-active" : ""} ${message.read ? "" : "is-unread"}`}
                onClick={() => {
                  onChange((current) => ({ ...current, activeMessageId: message.id }));
                  updateMessage(message.id, { read: true });
                }}
              >
                <span>
                  <strong>{message.from}</strong>
                  <small>{message.time}</small>
                </span>
                <b>{message.subject}</b>
                <em>{message.body}</em>
                {attachmentCount > 0 ? (
                  <small className="message-attachment-count">
                    <Paperclip size={13} />
                    {attachmentCount}
                  </small>
                ) : null}
              </button>
            );
          })}
          {visibleMessages.length === 0 ? <p className="empty-state">В этой папке нет писем.</p> : null}
        </div>
      </section>

      <section className="message-reader" aria-label="Чтение письма">
        {activeMessage ? (
          <>
            <div className="message-actions">
              <button type="button" onClick={() => updateMessage(activeMessage.id, { read: !activeMessage.read })}>
                <MailOpen size={16} />
                {activeMessage.read ? "Отметить непрочитанным" : "Отметить прочитанным"}
              </button>
              <button type="button" onClick={() => updateMessage(activeMessage.id, { flagged: !activeMessage.flagged })}>
                <Flag size={16} />
                {activeMessage.flagged ? "Снять флаг" : "Поставить флаг"}
              </button>
              <button type="button" onClick={() => updateMessage(activeMessage.id, { folder: "archive" })}>
                <Archive size={16} />
                В архив
              </button>
              <button type="button" onClick={() => void saveEml(activeMessage)}>
                <Download size={16} />
                Сохранить EML
              </button>
              <button type="button" onClick={() => void exportPdf()}>
                <FileText size={16} />
                Экспорт PDF
              </button>
            </div>
            <article className="message-content">
              <h2>{activeMessage.subject}</h2>
              <p className="muted">
                От: {activeMessage.from} · Кому: {activeMessage.to} · {activeMessage.time}
              </p>
              <p>{activeMessage.body}</p>
              {activeAttachments.length > 0 ? (
                <section className="attachments-panel" aria-label="Вложения письма">
                  <h3>Вложения</h3>
                  <ul className="attachment-list">
                    {activeAttachments.map((attachment) => (
                      <li key={attachment.id} className="attachment-item">
                        <span className="attachment-main">
                          <Paperclip size={16} />
                          <span>
                            <strong>{attachment.fileName}</strong>
                            <small>
                              {attachment.contentType} · {formatBytes(attachment.size)}
                            </small>
                          </span>
                        </span>
                        <button type="button" onClick={() => downloadAttachment(attachment)} aria-label={`Скачать ${attachment.fileName}`}>
                          <Download size={16} />
                        </button>
                      </li>
                    ))}
                  </ul>
                </section>
              ) : null}
            </article>
          </>
        ) : (
          <p className="empty-state">Выберите письмо.</p>
        )}

        <form
          className="compose-panel"
          onSubmit={(event) => {
            event.preventDefault();
            sendDraft();
          }}
        >
          <h3>Новое письмо</h3>
          <input value={draft.to} onChange={(event) => setDraft({ ...draft, to: event.target.value })} placeholder="Кому" aria-label="Кому" />
          <input
            value={draft.subject}
            onChange={(event) => setDraft({ ...draft, subject: event.target.value })}
            placeholder="Тема"
            aria-label="Тема"
          />
          <textarea
            value={draft.body}
            onChange={(event) => setDraft({ ...draft, body: event.target.value })}
            placeholder="Текст письма"
            aria-label="Текст письма"
          />
          <input
            ref={draftAttachmentInputRef}
            className="hidden-file-input"
            type="file"
            multiple
            onChange={(event) => void addDraftAttachments(event.target.files)}
            aria-label="Добавить вложения"
          />
          <div className="compose-attachments">
            <button type="button" onClick={() => draftAttachmentInputRef.current?.click()}>
              <Paperclip size={16} />
              Добавить файлы
            </button>
            {draft.attachments.length > 0 ? (
              <ul className="attachment-list compact">
                {draft.attachments.map((attachment) => (
                  <li key={attachment.id} className="attachment-item">
                    <span className="attachment-main">
                      <Paperclip size={16} />
                      <span>
                        <strong>{attachment.fileName}</strong>
                        <small>{formatBytes(attachment.size)}</small>
                      </span>
                    </span>
                    <button type="button" onClick={() => removeDraftAttachment(attachment.id)} aria-label={`Удалить ${attachment.fileName}`}>
                      <X size={16} />
                    </button>
                  </li>
                ))}
              </ul>
            ) : null}
          </div>
          <button className="primary-command" type="submit" disabled={!draft.to.trim() || !draft.subject.trim()}>
            <Send size={16} />
            Отправить
          </button>
        </form>
      </section>
    </div>
  );
}
