import { Modal, Setting, TFile, TAbstractFile } from "obsidian";
import ExcalidrawPlugin from "src/core/main";
import { getIMGFilename } from "src/utils/fileUtils";
import { setElementDisplay } from "src/utils/htmlUtils";
import { addYouTubeThumbnail } from "src/utils/utils";

const haveLinkedFilesChanged = (
  depth: number,
  mtime: number,
  path: string,
  sourceList: Set<string>,
  plugin: ExcalidrawPlugin,
): boolean => {
  if (depth++ > 5) {
    return false;
  }
  sourceList.add(path);
  const links = plugin.app.metadataCache.resolvedLinks[path];
  if (!links) {
    return false;
  }
  for (const link of Object.keys(links)) {
    if (sourceList.has(link)) {
      continue;
    }
    const file = plugin.app.vault.getAbstractFileByPath(link);
    if (!file || !(file instanceof TFile)) {
      continue;
    }
    console.log(path, {
      mtimeLinked: file.stat.mtime,
      mtimeSource: mtime,
      path: file.path,
    });
    if (file.stat.mtime > mtime) {
      return true;
    }
    if (plugin.isExcalidrawFile(file)) {
      if (haveLinkedFilesChanged(depth, mtime, file.path, sourceList, plugin)) {
        return true;
      }
    }
  }
  return false;
};

const listOfOutOfSyncImgExports = async (
  plugin: ExcalidrawPlugin,
  recursive: boolean,
  statusEl: HTMLParagraphElement,
): Promise<TFile[]> => {
  const app = plugin.app;

  const publish = app.internalPlugins.plugins.publish?.instance;
  if (!publish) {
    return;
  }
  const list = await publish.apiList();
  if (!list || !list.files) {
    return;
  }
  const outOfSyncFiles = new Set<TFile>();
  const allFiles = list.files.filter(
    (f: TAbstractFile) => f.path.endsWith(".svg") || f.path.endsWith(".png"),
  );
  const totalCount = allFiles.length;
  allFiles.forEach((f: TAbstractFile, idx: number) => {
    const maybeExcalidraFilePath = getIMGFilename(f.path, "md");
    const imgFile = app.vault.getAbstractFileByPath(f.path);
    const excalidrawFile = app.vault.getAbstractFileByPath(
      maybeExcalidraFilePath,
    );
    statusEl.innerText = `Status: ${idx + 1}/${totalCount} ${imgFile ? imgFile.name : f.path}`;
    if (
      !excalidrawFile ||
      !imgFile ||
      !(excalidrawFile instanceof TFile) ||
      !(imgFile instanceof TFile)
    ) {
      return;
    }
    if (excalidrawFile.stat.mtime <= imgFile.stat.mtime) {
      if (!recursive) {
        return;
      }
      if (
        !haveLinkedFilesChanged(
          0,
          excalidrawFile.stat.mtime,
          excalidrawFile.path,
          new Set<string>(),
          plugin,
        )
      ) {
        return;
      }
    }
    outOfSyncFiles.add(excalidrawFile);
  });
  return Array.from(outOfSyncFiles);
};

export class PublishOutOfDateFilesDialog extends Modal {
  constructor(private plugin: ExcalidrawPlugin) {
    super(plugin.app);
  }

  onClose() {}

  onOpen() {
    this.containerEl.classList.add("excalidraw-release");
    this.titleEl.setText(`Out of Date SVG Files`);
    void this.createForm(false);
  }

  async createForm(recursive: boolean) {
    const detailsEl = this.contentEl.createEl("details");
    detailsEl.createEl("summary", {
      text: "Video about Obsidian Publish support",
    });
    detailsEl.createEl("br");
    addYouTubeThumbnail(detailsEl, "JC1E-jeiWhI");
    const p = this.contentEl.createEl("p", { text: "Collecting data..." });
    const statusEl = this.contentEl.createEl("p", { text: "Status: " });
    const files = await listOfOutOfSyncImgExports(
      this.plugin,
      recursive,
      statusEl,
    );
    setElementDisplay(statusEl, "none");

    if (!files || files.length === 0) {
      p.innerText = "No out of date files found.";
      const div = this.contentEl.createDiv({
        cls: "excalidraw-prompt-buttons-div",
      });
      const bClose = div.createEl("button", {
        text: "Close",
        cls: "excalidraw-prompt-button",
      });
      bClose.onclick = () => {
        this.close();
      };
      if (!recursive) {
        const bRecursive = div.createEl("button", {
          text: "Check Recursive",
          cls: "excalidraw-prompt-button",
        });
        bRecursive.onclick = () => {
          this.contentEl.empty();
          void this.createForm(true);
        };
      }
      return;
    }

    const filesMap = new Map<TFile, boolean>();
    p.innerText = "Select files to open.";
    files.forEach((f: TFile) => {
      filesMap.set(f, true);
      new Setting(this.contentEl).setName(f.path).addToggle((toggle) =>
        toggle.setValue(true).onChange((value) => {
          filesMap.set(f, value);
        }),
      );
    });

    const div = this.contentEl.createDiv({
      cls: "excalidraw-prompt-buttons-div",
    });
    const bClose = div.createEl("button", {
      text: "Close",
      cls: "excalidraw-prompt-button",
    });
    bClose.onclick = () => {
      this.close();
    };
    if (!recursive) {
      const bRecursive = div.createEl("button", {
        text: "Check Recursive",
        cls: "excalidraw-prompt-button",
      });
      bRecursive.onclick = () => {
        this.contentEl.empty();
        void this.createForm(true);
      };
    }
    const bOpen = div.createEl("button", {
      text: "Open Selected",
      cls: "excalidraw-prompt-button",
    });
    bOpen.onclick = () => {
      filesMap.forEach((value: boolean, key: TFile) => {
        if (value) {
          this.plugin.openDrawing(key, "new-tab", true);
        }
      });
      this.close();
    };
  }
}
