import * as vscode from "vscode";
import type { EDMApi, EDMFolderAsset, EDMFolderTemplate } from "./api";

/**
 * The EDM store as a tree in the VS Code sidebar.
 *
 * Mirrors the console's folder browser: a folder's own subfolders, its own
 * templates, and the images those templates use. Children are fetched lazily,
 * one folder at a time, so opening the view never pulls the whole store.
 *
 * On images: they have no folder of their own. They are content-addressed
 * objects in one flat bucket so a shared logo is stored once and a URL already
 * in someone's inbox never breaks. What appears under a folder here is derived
 * — the images its templates reference — not a directory listing.
 */

export type EDMNode =
  | { kind: "folder"; id: string | null; label: string }
  | { kind: "template"; template: EDMFolderTemplate }
  | { kind: "asset"; asset: EDMFolderAsset }
  | { kind: "message"; label: string };

export class EDMTreeProvider implements vscode.TreeDataProvider<EDMNode> {
  private readonly _onDidChangeTreeData = new vscode.EventEmitter<EDMNode | undefined>();
  readonly onDidChangeTreeData = this._onDidChangeTreeData.event;

  constructor(private readonly api: EDMApi) {}

  refresh(): void {
    this._onDidChangeTreeData.fire(undefined);
  }

  getTreeItem(node: EDMNode): vscode.TreeItem {
    if (node.kind === "message") {
      const item = new vscode.TreeItem(node.label, vscode.TreeItemCollapsibleState.None);
      item.contextValue = "karmaEdmMessage";
      return item;
    }

    if (node.kind === "folder") {
      const item = new vscode.TreeItem(
        node.label,
        vscode.TreeItemCollapsibleState.Collapsed,
      );
      item.iconPath = new vscode.ThemeIcon("folder");
      item.contextValue = "karmaEdmFolder";
      return item;
    }

    if (node.kind === "template") {
      const item = new vscode.TreeItem(
        node.template.name,
        vscode.TreeItemCollapsibleState.None,
      );
      item.description = node.template.subject ?? "";
      item.iconPath = new vscode.ThemeIcon("mail");
      item.contextValue = "karmaEdmTemplate";
      item.command = {
        command: "karmaEdm.openTemplate",
        title: "Open",
        arguments: [node.template],
      };
      // An unpublished template has no active version, so the mail worker has
      // nothing to render — usually a batch import that hit a missing image.
      item.tooltip = new vscode.MarkdownString(
        [
          `**${node.template.name}**`,
          "",
          `Subject: ${node.template.subject || "_none_"}`,
          `ID: \`${node.template.id}\``,
          node.template.active_version_id ? "" : "\n⚠ **Unpublished** — cannot be sent.",
        ].join("\n"),
      );
      return item;
    }

    const filename = node.asset.path.split("/").pop() ?? node.asset.path;
    const item = new vscode.TreeItem(filename, vscode.TreeItemCollapsibleState.None);
    item.description = `${node.asset.usedBy.length} use${node.asset.usedBy.length === 1 ? "" : "s"}`;
    item.iconPath = new vscode.ThemeIcon("file-media");
    item.contextValue = "karmaEdmAsset";
    item.resourceUri = vscode.Uri.parse(node.asset.url);
    item.tooltip = new vscode.MarkdownString(
      [
        `**${node.asset.original}**`,
        "",
        `Used by: ${node.asset.usedBy.join(", ")}`,
        "",
        `${node.asset.url}`,
      ].join("\n"),
    );
    item.command = {
      command: "karmaEdm.openAsset",
      title: "Preview",
      arguments: [node.asset],
    };
    return item;
  }

  async getChildren(node?: EDMNode): Promise<EDMNode[]> {
    // Only folders have children; templates and assets are leaves.
    if (node && node.kind !== "folder") return [];

    if (!(await this.api.hasCookie())) {
      return [{ kind: "message", label: "Not signed in — run “Karma EDM: Set console session”" }];
    }

    try {
      const data = await this.api.browse(node ? node.id : null);
      return [
        ...data.folders.map(
          (f): EDMNode => ({ kind: "folder", id: f.id, label: f.name }),
        ),
        ...data.templates.map((t): EDMNode => ({ kind: "template", template: t })),
        ...data.assets.map((a): EDMNode => ({ kind: "asset", asset: a })),
      ];
    } catch (err) {
      // Rendered as a node rather than thrown: an error toast per expanded
      // folder would be unusable, and the tree still needs to show something.
      return [{ kind: "message", label: `Error: ${(err as Error).message}` }];
    }
  }
}
