/**
 * Manual export/import of the whole book.
 *
 * This exists so the data is never hostage to the sync code being correct.
 * Whatever the server or the browser is doing, a file on disk is a file on
 * disk.
 */
import { useWorkspace } from "./store";
import type { WorkspaceData } from "./types";

interface BackupFile {
  kind: "fieldbook-backup";
  version: 1;
  exportedAt: string;
  data: WorkspaceData;
}

function currentBook(): WorkspaceData {
  const s = useWorkspace.getState();
  return {
    projects: s.projects,
    tasks: s.tasks,
    notes: s.notes,
    reminders: s.reminders,
    boards: s.boards,
    waiting: s.waiting,
    scratch: s.scratch,
    focusTaskId: s.focusTaskId,
  };
}

export function exportBook(): void {
  const payload: BackupFile = {
    kind: "fieldbook-backup",
    version: 1,
    exportedAt: new Date().toISOString(),
    data: currentBook(),
  };
  const blob = new Blob([JSON.stringify(payload, null, 2)], { type: "application/json" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = `fieldbook-${new Date().toISOString().slice(0, 19).replace(/[:T]/g, "-")}.json`;
  a.click();
  // Revoke on a delay: revoking synchronously can cancel the download in some
  // browsers before it has read the blob.
  setTimeout(() => URL.revokeObjectURL(url), 10_000);
}

/** Accepts an export file, or a bare book object for hand-edited JSON. */
export function parseBackup(text: string): WorkspaceData {
  const parsed = JSON.parse(text) as unknown;
  const candidate =
    parsed && typeof parsed === "object" && "data" in (parsed as Record<string, unknown>)
      ? (parsed as BackupFile).data
      : (parsed as WorkspaceData);

  if (!candidate || typeof candidate !== "object") throw new Error("not a Fieldbook backup");
  for (const key of ["projects", "tasks", "notes", "reminders", "boards"] as const) {
    if (!Array.isArray(candidate[key])) throw new Error(`missing or invalid "${key}"`);
  }
  if (candidate.waiting !== undefined && !Array.isArray(candidate.waiting)) {
    throw new Error('invalid "waiting"');
  }
  if (candidate.scratch !== undefined && !Array.isArray(candidate.scratch)) {
    throw new Error('invalid "scratch"');
  }
  // Backups from before these sections existed simply have none.
  return { ...candidate, waiting: candidate.waiting ?? [], scratch: candidate.scratch ?? [] };
}

/** Replaces the book. The caller is expected to have confirmed with the user. */
export function importBook(data: WorkspaceData): void {
  useWorkspace.getState().importData(data);
}
