<script lang="ts">
  import { goto } from "$app/navigation";
  import { unlockVaultWorkspace } from "$lib/backend/auth";
  import AppModal from "$lib/components/AppModal.svelte";
  import { deleteEntryTemplate, loadEntryTemplate, saveEntryTemplate } from "$lib/backend/templates";
  import { deleteEntryByStoreId, entriesStore, getDefaultEntry, hydrateEntries, loadEntryByStoreId, saveEntryFromStore } from "$lib/stores/entries";
  import { deleteFragmentByStoreId, hydrateFragments } from "$lib/stores/fragments";
  import { deleteListByStoreId, hydrateLists, updateListByStoreId } from "$lib/stores/lists";
  import { isVaultReady, setFlushCallback, setVaultSession } from "$lib/stores/session";
  import { deleteTodoListByStoreId, hydrateTodos } from "$lib/stores/todos";
  import Navbar from "$lib/components/Navbar.svelte";
  import SidePanel from "$lib/components/SidePanel.svelte";
  import EditorPanel from "$lib/components/EditorPanel.svelte";
  import { onMount } from "svelte";
  import { get } from "svelte/store";

  type OpenDocument = {
    id: string;
    label: string;
    initialContent: string;
  };

  const initialEntry = getDefaultEntry(get(entriesStore));

  let selectedSection = "entries";
  let panelOpen = true;
  let editMode = false;
  let activeDocumentId = initialEntry?.id ?? "entries/daily-notes";
  let activeDocumentLabel = initialEntry?.label ?? "Daily Notes";
  let openDocuments: Record<string, string> = initialEntry
    ? { [initialEntry.id]: initialEntry.initialContent }
    : { "entries/daily-notes": "# Daily Notes\n\nStart writing today's entry..." };
  let modalOpen = false;
  let modalTitle = "";
  let modalMessage = "";
  let modalConfirmText = "OK";
  let modalCancelText = "Cancel";
  let modalShowCancel = false;
  let modalTone: "default" | "danger" = "default";
  let modalAction: "logout-confirm" | "logout-info" | "unlock-vault" | "delete-confirm" | null = null;
  let modalInputEnabled = false;
  let modalInputType = "text";
  let modalInputPlaceholder = "";
  let modalInputAriaLabel = "Modal input";
  let modalInputValue = "";
  let unlockResolver: ((password: string | null) => void) | null = null;
  let fragmentBootstrapInFlight = false;
  let pendingDeleteItemId = "";
  let templateRefreshToken = 0;

  function toTemplatePath(id: string): string | null {
    const prefix = "entries/template-file/";
    if (!id.startsWith(prefix)) return null;
    const encoded = id.slice(prefix.length).trim();
    if (!encoded) return null;
    try {
      const decoded = decodeURIComponent(encoded);
      return decoded || null;
    } catch {
      return null;
    }
  }

  function templateNameFromPath(path: string): string {
    const fileName = path.split(/[\\/]/).pop() ?? path;
    return fileName.replace(/\.template\.md$/i, "");
  }

  function showModal(options: {
    action: "logout-confirm" | "logout-info" | "unlock-vault" | "delete-confirm";
    title: string;
    message: string;
    confirmText?: string;
    cancelText?: string;
    showCancel?: boolean;
    tone?: "default" | "danger";
    inputEnabled?: boolean;
    inputType?: string;
    inputPlaceholder?: string;
    inputAriaLabel?: string;
    inputValue?: string;
  }) {
    modalAction = options.action;
    modalTitle = options.title;
    modalMessage = options.message;
    modalConfirmText = options.confirmText ?? "OK";
    modalCancelText = options.cancelText ?? "Cancel";
    modalShowCancel = options.showCancel ?? false;
    modalTone = options.tone ?? "default";
    modalInputEnabled = options.inputEnabled ?? false;
    modalInputType = options.inputType ?? "text";
    modalInputPlaceholder = options.inputPlaceholder ?? "";
    modalInputAriaLabel = options.inputAriaLabel ?? "Modal input";
    modalInputValue = options.inputValue ?? "";
    modalOpen = true;
  }

  function closeModal() {
    modalOpen = false;
    modalAction = null;
    modalInputEnabled = false;
    modalInputType = "text";
    modalInputPlaceholder = "";
    modalInputAriaLabel = "Modal input";
    modalInputValue = "";
    pendingDeleteItemId = "";
  }

  async function handleModalConfirm() {
    if (modalAction === "logout-confirm") {
      showModal({
        action: "logout-info",
        title: "Logout Requested",
        message: "You have been logged out.",
        confirmText: "Close"
      });
      return;
    }

    if (modalAction === "unlock-vault") {
      const value = modalInputValue.trim();
      if (!value) return;
      const resolve = unlockResolver;
      unlockResolver = null;
      closeModal();
      resolve?.(value);
      return;
    }

    if (modalAction === "delete-confirm") {
      const id = pendingDeleteItemId;
      closeModal();
      await performDelete(id);
      return;
    }

    closeModal();
  }

  function handleModalCancel() {
    if (modalAction === "unlock-vault") {
      const resolve = unlockResolver;
      unlockResolver = null;
      closeModal();
      resolve?.(null);
      return;
    }

    closeModal();
  }

  function requestVaultPassword(): Promise<string | null> {
    return new Promise((resolve) => {
      unlockResolver = resolve;
      showModal({
        action: "unlock-vault",
        title: "Unlock Vault",
        message: "Enter your vault password to load journal data.",
        confirmText: "Unlock",
        cancelText: "Cancel",
        showCancel: true,
        inputEnabled: true,
        inputType: "password",
        inputPlaceholder: "Vault password",
        inputAriaLabel: "Vault password",
        inputValue: ""
      });
    });
  }

  function isLockedError(error: unknown): boolean {
    const message = error instanceof Error ? error.message : String(error);
    const normalized = message.toLowerCase();
    return normalized.includes("database is locked") || normalized.includes("incorrect vault password");
  }

  async function bootstrapFragmentsWithUnlock(maxAttempts = 3) {
    if (fragmentBootstrapInFlight) return;

    if (isVaultReady()) {
      try {
        await hydrateEntries();
        templateRefreshToken += 1;
        const firstEntry = getDefaultEntry(get(entriesStore));
        if (firstEntry && activeDocumentId === "entries/daily-notes") {
          await handleOpenDocument(firstEntry);
        }
        await hydrateFragments();
        await hydrateLists().catch(() => {});
        await hydrateTodos().catch(() => {});
      } catch (error) {
        console.error("Hydration failed:", error);
      }
      return;
    }

    fragmentBootstrapInFlight = true;
    try {
      let attempts = 0;
      while (attempts < maxAttempts) {
        try {
          const password = await requestVaultPassword();
          if (!password) return;

          await unlockVaultWorkspace(password);
          setVaultSession(password);

          await hydrateEntries();
          templateRefreshToken += 1;
          const firstEntry = getDefaultEntry(get(entriesStore));
          if (firstEntry && activeDocumentId === "entries/daily-notes") {
            await handleOpenDocument(firstEntry);
          }

          await hydrateFragments();
          await hydrateLists().catch(() => {});
          await hydrateTodos().catch(() => {});
          return;
        } catch (error) {
          if (!isLockedError(error)) return;
          attempts += 1;
        }
      }

    } finally {
      fragmentBootstrapInFlight = false;
    }
  }

  async function saveCurrentDocument() {
    if (!activeDocumentId) return;
    const content = openDocuments[activeDocumentId];
    if (!content?.trim()) return;

    try {
      if (selectedSection === "entries" && activeDocumentId.startsWith("entries/template-draft-")) {
        const draft = get(entriesStore).find((item) => item.id === activeDocumentId);
        const draftLabel = (draft?.label ?? activeDocumentLabel ?? "").trim();
        const templateName = draftLabel.replace(/_template$/i, "").trim() || draftLabel;
        await saveEntryTemplate({
          name: templateName,
          content
        });
        templateRefreshToken += 1;
        entriesStore.update((items) => items.filter((item) => item.id !== activeDocumentId));
        const { [activeDocumentId]: _, ...rest } = openDocuments;
        openDocuments = rest;
        activeDocumentId = "";
        activeDocumentLabel = "";
        editMode = false;
      } else if (selectedSection === "entries" && activeDocumentId.startsWith("entries/template-file/")) {
        const filePath = toTemplatePath(activeDocumentId);
        if (!filePath) return;
        await saveEntryTemplate({
          name: templateNameFromPath(filePath),
          content,
          filePath
        });
        templateRefreshToken += 1;
      } else if (selectedSection === "entries" && (activeDocumentId.startsWith("entries/file/") || activeDocumentId.startsWith("entries/draft-"))) {
        const saved = await saveEntryFromStore(activeDocumentId, content, "Overwrite");
        if (saved && saved.id !== activeDocumentId) {
          const { [activeDocumentId]: _, ...rest } = openDocuments;
          openDocuments = { ...rest, [saved.id]: saved.initialContent };
          activeDocumentId = saved.id;
          activeDocumentLabel = saved.label;
        }
      } else if (selectedSection === "lists" && activeDocumentId.startsWith("lists/") && !activeDocumentId.startsWith("lists/draft-")) {
        await updateListByStoreId(activeDocumentId, undefined, content);
      }
    } catch {
      // best-effort save
    }
  }

  async function handleSelect(id: string) {
    if (id === "account" || id === "settings") {
      goto(`/${id}`);
      return;
    }

    if (id === "logout") {
      showModal({
        action: "logout-confirm",
        title: "Confirm Logout",
        message: "Are you sure you want to log out?",
        confirmText: "Log Out",
        cancelText: "Cancel",
        showCancel: true,
        tone: "danger"
      });
      return;
    }

    if (selectedSection === id) {
      panelOpen = !panelOpen;
      return;
    }

    await saveCurrentDocument();
    selectedSection = id;
    panelOpen = true;
    activeDocumentId = "";
    activeDocumentLabel = "";
    editMode = false;
  }

  async function handleOpenDocument(doc: OpenDocument) {
    const prevActiveId = activeDocumentId;
    await saveCurrentDocument();
    editMode = false;

    // If saveCurrentDocument promoted a draft to a file-backed entry and the
    // caller passed the now-stale draft reference, the editor is already
    // showing the promoted entry — nothing more to do.
    if (doc.id === prevActiveId && activeDocumentId !== prevActiveId) {
      return;
    }

    let resolvedDoc = doc;
    if (selectedSection === "entries" && doc.id.startsWith("entries/file/") && !doc.initialContent) {
      try {
        const loaded = await loadEntryByStoreId(doc.id);
        if (loaded) {
          resolvedDoc = loaded;
        }
      } catch {
        // entry content will use initialContent fallback
      }
    } else if (selectedSection === "entries" && doc.id.startsWith("entries/template-file/") && !doc.initialContent) {
      try {
        const filePath = toTemplatePath(doc.id);
        if (filePath) {
          const loaded = await loadEntryTemplate(filePath);
          resolvedDoc = {
            id: doc.id,
            label: loaded.fileName.replace(/\.template\.md$/i, ""),
            initialContent: loaded.content
          };
        }
      } catch {
        // template content will use initialContent fallback
      }
    }

    if (!(resolvedDoc.id in openDocuments)) {
      openDocuments = { ...openDocuments, [resolvedDoc.id]: resolvedDoc.initialContent };
    }
    activeDocumentId = resolvedDoc.id;
    activeDocumentLabel = resolvedDoc.label;
  }

  function handleDocumentContentChange(content: string) {
    openDocuments = { ...openDocuments, [activeDocumentId]: content };
  }

  function handleDeleteDocument(id: string) {
    const { [id]: _, ...remaining } = openDocuments;
    openDocuments = remaining;
  }

  async function performDelete(id: string) {
    try {
      let ok = false;
      if (selectedSection === "entries") {
        const templatePath = toTemplatePath(id);
        if (templatePath) {
          ok = await deleteEntryTemplate(templatePath);
          if (ok) templateRefreshToken += 1;
        } else if (id.startsWith("entries/template-draft-")) {
          entriesStore.update((items) => items.filter((item) => item.id !== id));
          ok = true;
        } else {
          ok = await deleteEntryByStoreId(id);
        }
      } else if (selectedSection === "todos") {
        ok = await deleteTodoListByStoreId(id);
      } else if (selectedSection === "lists") {
        ok = await deleteListByStoreId(id);
      } else if (selectedSection === "fragments") {
        ok = await deleteFragmentByStoreId(id);
      }
      if (!ok) return;

      handleDeleteDocument(id);
      if (activeDocumentId === id) {
        activeDocumentId = "";
        activeDocumentLabel = "";
        editMode = false;
      }
    } catch (error) {
      console.error("Delete failed:", error);
    }
  }

  async function handleEditItem(doc: OpenDocument) {
    if (doc.id !== activeDocumentId) {
      await handleOpenDocument(doc);
    }
    editMode = true;
  }

  function handleDeleteItem(doc: { id: string; label: string }) {
    pendingDeleteItemId = doc.id;
    showModal({
      action: "delete-confirm",
      title: "Confirm Delete",
      message: `Are you sure you want to delete "${doc.label}"? This action cannot be undone.`,
      confirmText: "Delete",
      cancelText: "Cancel",
      showCancel: true,
      tone: "danger"
    });
  }

  onMount(() => {
    setFlushCallback(saveCurrentDocument);
    bootstrapFragmentsWithUnlock();
  });
</script>

<div class="app-shell" class:panel-closed={!panelOpen}>
  <Navbar activeSection={selectedSection} onSelect={handleSelect} />
  {#if panelOpen}
    <SidePanel
      activeSection={selectedSection}
      {activeDocumentId}
      {templateRefreshToken}
      onOpenDocument={handleOpenDocument}
      onEditItem={handleEditItem}
      onDeleteItem={handleDeleteItem}
    />
  {/if}
  <EditorPanel
    activeSection={selectedSection}
    openDocumentId={activeDocumentId}
    openDocumentName={activeDocumentLabel}
    openDocumentContent={openDocuments[activeDocumentId] ?? ""}
    onDocumentContentChange={handleDocumentContentChange}
    onOpenDocument={handleOpenDocument}
    onDeleteDocument={handleDeleteDocument}
    previewOnly={!editMode}
  />
</div>

<AppModal
  open={modalOpen}
  title={modalTitle}
  message={modalMessage}
  confirmText={modalConfirmText}
  cancelText={modalCancelText}
  showCancel={modalShowCancel}
  tone={modalTone}
  inputEnabled={modalInputEnabled}
  inputType={modalInputType}
  inputPlaceholder={modalInputPlaceholder}
  inputAriaLabel={modalInputAriaLabel}
  bind:inputValue={modalInputValue}
  onConfirm={handleModalConfirm}
  onCancel={handleModalCancel}
/>

<style>
  .app-shell {
    height: 100vh;
    overflow: hidden;
  }

  .app-shell :global(.side-panel),
  .app-shell :global(.editor-panel) {
    min-height: 0;
    min-width: 0;
  }
</style>
