/**
 * Axint App Generator
 *
 * Transforms IRApp into a clean, idiomatic SwiftUI @main App struct.
 * Follows the same string-template approach as the view/widget generators.
 */

import type { IRApp, IRScene } from "./types.js";
import { irTypeToSwift } from "./types.js";
import { escapeSwiftString, generatedFileHeader } from "./generator.js";

/**
 * Generate a SwiftUI App source file from an IRApp.
 */
export function generateSwiftApp(app: IRApp): string {
  const lines: string[] = [];

  lines.push(...generatedFileHeader(`${app.name}App.swift`));
  lines.push(``);
  lines.push(`import SwiftUI`);
  lines.push(``);

  lines.push(`@main`);
  lines.push(`struct ${app.name}App: App {`);

  // AppStorage properties
  if (app.appStorage && app.appStorage.length > 0) {
    for (const s of app.appStorage) {
      const swift = irTypeToSwift(s.type);
      if (s.defaultValue !== undefined) {
        lines.push(
          `    @AppStorage("${escapeSwiftString(s.key)}") private var ${s.name}: ${swift} = ${formatLiteral(s.defaultValue)}`
        );
      } else {
        lines.push(
          `    @AppStorage("${escapeSwiftString(s.key)}") private var ${s.name}: ${swift}`
        );
      }
    }
    lines.push(``);
  }

  lines.push(`    var body: some Scene {`);

  // Group scenes by platform guard
  const ungrouped = app.scenes.filter((s) => !s.platformGuard);
  const macOnly = app.scenes.filter((s) => s.platformGuard === "macOS");
  const iosOnly = app.scenes.filter((s) => s.platformGuard === "iOS");
  const visionOnly = app.scenes.filter((s) => s.platformGuard === "visionOS");

  for (const scene of ungrouped) {
    lines.push(...generateScene(scene, 2));
  }

  if (macOnly.length > 0) {
    lines.push(`        #if os(macOS)`);
    for (const scene of macOnly) {
      lines.push(...generateScene(scene, 2));
    }
    lines.push(`        #endif`);
  }

  if (iosOnly.length > 0) {
    lines.push(`        #if os(iOS)`);
    for (const scene of iosOnly) {
      lines.push(...generateScene(scene, 2));
    }
    lines.push(`        #endif`);
  }

  if (visionOnly.length > 0) {
    lines.push(`        #if os(visionOS)`);
    for (const scene of visionOnly) {
      lines.push(...generateScene(scene, 2));
    }
    lines.push(`        #endif`);
  }

  lines.push(`    }`);
  lines.push(`}`);
  lines.push(``);

  return lines.join("\n");
}

function generateScene(scene: IRScene, depth: number): string[] {
  const indent = "    ".repeat(depth);
  const lines: string[] = [];

  switch (scene.sceneKind) {
    case "windowGroup": {
      const titleArg = scene.title ? `"${escapeSwiftString(scene.title)}"` : undefined;
      const idArg =
        scene.name && !scene.isDefault
          ? `id: "${escapeSwiftString(scene.name)}"`
          : undefined;
      const args = [titleArg, idArg].filter(Boolean).join(", ");
      const argStr = args ? `(${args})` : "";

      lines.push(`${indent}WindowGroup${argStr} {`);
      lines.push(`${indent}    ${scene.rootView}()`);
      lines.push(`${indent}}`);
      break;
    }

    case "window": {
      const title = scene.title || scene.name || "Window";
      const id = scene.name || scene.rootView.toLowerCase();
      lines.push(
        `${indent}Window("${escapeSwiftString(title)}", id: "${escapeSwiftString(id)}") {`
      );
      lines.push(`${indent}    ${scene.rootView}()`);
      lines.push(`${indent}}`);
      break;
    }

    case "documentGroup": {
      // Use the scene's documentType when specified, otherwise derive from the root view name
      const docType = scene.documentType || `${scene.rootView}Document`;
      lines.push(`${indent}DocumentGroup(newDocument: { ${docType}() }) { file in`);
      lines.push(`${indent}    ${scene.rootView}(document: file.$document)`);
      lines.push(`${indent}}`);
      break;
    }

    case "settings": {
      lines.push(`${indent}Settings {`);
      lines.push(`${indent}    ${scene.rootView}()`);
      lines.push(`${indent}}`);
      break;
    }
  }

  return lines;
}

function formatLiteral(value: unknown): string {
  if (typeof value === "string") return `"${escapeSwiftString(value)}"`;
  if (typeof value === "number") return `${value}`;
  if (typeof value === "boolean") return value ? "true" : "false";
  return `"${escapeSwiftString(String(value))}"`;
}
