import path from "node:path";
import fs from "node:fs";
import { runMdschema } from "../mdschema";
import { ALL_SCHEMAS } from "../schemas";
import { MODULE_PATHS, APP_PATHS } from "./lib/paths";

export const MODULE_DOC_TYPES = ["feature", "command", "model", "query"] as const;
export const APP_DOC_TYPES = ["actors", "business-flow", "story", "screen", "resolver"] as const;
export const ALL_DOC_TYPES = [...MODULE_DOC_TYPES, ...APP_DOC_TYPES] as const;

export type DocType = (typeof ALL_DOC_TYPES)[number];

const MODULE_DIR_MAP: Record<string, string> = {
  feature: MODULE_PATHS.docs.features,
  command: MODULE_PATHS.docs.commands,
  model: MODULE_PATHS.docs.models,
  query: MODULE_PATHS.docs.queries,
};

const APP_DIR_MAP: Record<string, string> = {
  actors: APP_PATHS.docs.actors,
  "business-flow": APP_PATHS.docs.businessFlow,
  screen: APP_PATHS.docs.screen,
  resolver: APP_PATHS.docs.resolver,
};

export function resolveDocPath(
  type: DocType,
  name: string | undefined,
  modulePath: string,
): string {
  if (!name) {
    throw new Error(`Name is required for doc type "${type}"`);
  }

  if (type === "business-flow") {
    return path.join(modulePath, APP_PATHS.docs.businessFlow, name, "README.md");
  }

  if (type === "story") {
    const parts = name.split("/");
    if (parts.length !== 2) {
      throw new Error(
        `Story name must be "<flow>/<story>" (e.g., "onboarding/admin--create-user")`,
      );
    }
    return path.join(
      modulePath,
      APP_PATHS.docs.businessFlow,
      parts[0],
      APP_PATHS.docs.story,
      `${parts[1]}.md`,
    );
  }

  if (MODULE_DIR_MAP[type]) {
    return path.join(modulePath, MODULE_DIR_MAP[type], `${name}.md`);
  }

  if (APP_DIR_MAP[type]) {
    return path.join(modulePath, APP_DIR_MAP[type], `${name}.md`);
  }

  throw new Error(`Unknown doc type: ${type}`);
}

export async function runGenerateDoc(
  type: DocType,
  name: string | undefined,
  modulePath: string,
  cwd: string,
): Promise<number> {
  const outputPath = resolveDocPath(type, name, modulePath);
  const absoluteOutput = path.resolve(cwd, outputPath);

  if (fs.existsSync(absoluteOutput)) {
    console.error(`File already exists: ${outputPath}`);
    return 1;
  }

  const schemaPath = ALL_SCHEMAS[type];
  if (!schemaPath) {
    console.error(`No schema found for type: ${type}`);
    return 2;
  }

  try {
    fs.mkdirSync(path.dirname(absoluteOutput), { recursive: true });
  } catch (err) {
    console.error(
      `Failed to create directory: ${err instanceof Error ? err.message : String(err)}`,
    );
    return 1;
  }

  const { exitCode, stdout, stderr } = await runMdschema(
    ["generate", "--schema", schemaPath, "--output", absoluteOutput],
    cwd,
  );

  if (stdout.trim()) console.log(stdout);
  if (stderr.trim()) console.error(stderr);

  return exitCode;
}
