import { useMemo } from "react";
import { AppShell } from "./components/AppShell";
import { QOutlook } from "./features/qoutlook/QOutlook";
import { QPowerPoint } from "./features/qpowerpoint/QPowerPoint";
import { QWord } from "./features/qword/QWord";
import { QExcell } from "./features/qexcell/QExcell";
import { initialState } from "./data/sampleData";
import { usePersistentState } from "./hooks/usePersistentState";
import type { AppId, MailMessage, QOfficeState, SlideDeck, WordDocument, Workbook } from "./types";

const STORAGE_KEY = "qoffice-state-v1";

function migrateQOfficeState(state: QOfficeState): QOfficeState {
  const launchChecklistAttachments = initialState.mail.messages.find((message) => message.id === "mail-1")?.attachments;
  const sampleSheet = initialState.workbook.sheets.find((sheet) => sheet.id === "sheet-1");
  const sampleSlidesById = Object.fromEntries(initialState.deck.slides.map((slide) => [slide.id, slide]));
  const sampleWordHtml = initialState.word.html;
  const needsSampleWordColor =
    state.word.id === initialState.word.id &&
    sampleWordHtml.includes("Ключевой результат") &&
    !state.word.html.includes("Ключевой результат");

  let changed = false;
  if (needsSampleWordColor) {
    changed = true;
  }
  const messages = state.mail.messages.map((message) => {
    if (!launchChecklistAttachments || message.id !== "mail-1" || (message.attachments?.length ?? 0) > 0) {
      return message;
    }

    changed = true;
    return { ...message, attachments: launchChecklistAttachments };
  });

  const sheets =
    state.workbook.id === initialState.workbook.id && sampleSheet
      ? state.workbook.sheets.map((sheet) => {
          if (sheet.id !== "sheet-1") {
            return sheet;
          }

          const needsMergedCells = (sheet.mergedCells?.length ?? 0) === 0;
          const needsSampleCell = !sheet.cells.A8 && sampleSheet.cells.A8;
          const missingSampleFormats = Object.entries(sampleSheet.cellFormats ?? {}).filter(([address]) => !sheet.cellFormats?.[address]);
          const missingSampleCharts = (sampleSheet.charts ?? []).filter((chart) => !(sheet.charts ?? []).some((existingChart) => existingChart.id === chart.id));
          if (!needsMergedCells && !needsSampleCell && missingSampleFormats.length === 0 && missingSampleCharts.length === 0) {
            return sheet;
          }

          changed = true;
          return {
            ...sheet,
            cells: needsSampleCell ? { ...sheet.cells, A8: sampleSheet.cells.A8 } : sheet.cells,
            mergedCells: needsMergedCells ? sampleSheet.mergedCells : sheet.mergedCells,
            cellFormats:
              missingSampleFormats.length > 0
                ? {
                    ...sheet.cellFormats,
                    ...Object.fromEntries(missingSampleFormats)
                  }
                : sheet.cellFormats,
            charts: missingSampleCharts.length > 0 ? [...(sheet.charts ?? []), ...missingSampleCharts] : sheet.charts
          };
        })
      : state.workbook.sheets;

  const slides =
    state.deck.id === initialState.deck.id
      ? state.deck.slides.map((slide) => {
          const sampleSlide = sampleSlidesById[slide.id];
          if (!sampleSlide?.backgroundColor || slide.backgroundColor) {
            return slide;
          }

          changed = true;
          return { ...slide, backgroundColor: sampleSlide.backgroundColor };
        })
      : state.deck.slides;

  return changed
    ? {
        ...state,
        word: needsSampleWordColor ? { ...state.word, html: sampleWordHtml } : state.word,
        workbook: { ...state.workbook, sheets },
        deck: { ...state.deck, slides },
        mail: { ...state.mail, messages }
      }
    : state;
}

export function App() {
  const [state, setState] = usePersistentState<QOfficeState>(STORAGE_KEY, initialState, migrateQOfficeState);

  const status = useMemo(() => {
    const updatedAt =
      state.activeApp === "word"
        ? state.word.updatedAt
        : state.activeApp === "sheets"
          ? state.workbook.updatedAt
          : state.activeApp === "slides"
            ? state.deck.updatedAt
            : undefined;

    return {
      savedLabel: "Сохранено локально",
      updatedAt
    };
  }, [state]);

  function setActiveApp(activeApp: AppId) {
    setState((current) => ({ ...current, activeApp }));
  }

  function updateWord(word: WordDocument) {
    setState((current) => ({ ...current, word: { ...word, updatedAt: new Date().toISOString() } }));
  }

  function updateWorkbook(workbook: Workbook) {
    setState((current) => ({ ...current, workbook: { ...workbook, updatedAt: new Date().toISOString() } }));
  }

  function updateDeck(deck: SlideDeck) {
    setState((current) => ({ ...current, deck: { ...deck, updatedAt: new Date().toISOString() } }));
  }

  function updateMail(updater: (mail: QOfficeState["mail"]) => QOfficeState["mail"]) {
    setState((current) => ({ ...current, mail: updater(current.mail) }));
  }

  function setMailFolder(folder: MailMessage["folder"]) {
    updateMail((mail) => {
      const firstInFolder = mail.messages.find((message) => message.folder === folder);
      return {
        ...mail,
        activeFolder: folder,
        activeMessageId: firstInFolder?.id ?? mail.activeMessageId
      };
    });
  }

  const activeSurface =
    state.activeApp === "word" ? (
      <QWord document={state.word} onChange={updateWord} />
    ) : state.activeApp === "sheets" ? (
      <QExcell workbook={state.workbook} onChange={updateWorkbook} />
    ) : state.activeApp === "slides" ? (
      <QPowerPoint deck={state.deck} onChange={updateDeck} />
    ) : (
      <QOutlook mail={state.mail} onChange={updateMail} onFolderChange={setMailFolder} />
    );

  return (
    <AppShell activeApp={state.activeApp} onAppChange={setActiveApp} status={status}>
      {activeSurface}
    </AppShell>
  );
}
