/**
 * config/loader.ts — Three-layer config loading.
 *
 * Resolution order:
 *   1. Built-in defaults (ROLE_REGISTRY + DEFAULT_WORKFLOW)
 *   2. Workspace: <workspace>/projects/config.yaml
 *   3. Project:   <workspace>/projects/<project>/config.yaml
 *
 * Also supports legacy workflow.yaml files (merged into the workflow section).
 */
import fs from "node:fs/promises";
import path from "node:path";
import YAML from "yaml";
import { ROLE_REGISTRY } from "../roles/registry.js";
import { DEFAULT_WORKFLOW, type WorkflowConfig } from "../workflow.js";
import { mergeConfig } from "./merge.js";
import type { DevClawConfig, ResolvedConfig, ResolvedRoleConfig, RoleOverride } from "./types.js";

/**
 * Load and resolve the full DevClaw config for a project.
 *
 * Merges: built-in → workspace config.yaml → project config.yaml.
 * Also picks up legacy workflow.yaml files if no workflow section in config.yaml.
 */
export async function loadConfig(
  workspaceDir: string,
  projectName?: string,
): Promise<ResolvedConfig> {
  const projectsDir = path.join(workspaceDir, "projects");

  // Layer 1: built-in defaults
  const builtIn = buildDefaultConfig();

  // Layer 2: workspace config.yaml
  let merged = builtIn;
  const workspaceConfig = await readConfigFile(projectsDir);
  if (workspaceConfig) {
    merged = mergeConfig(merged, workspaceConfig);
  }

  // Legacy: workspace workflow.yaml (only if no workflow in config.yaml)
  if (!workspaceConfig?.workflow) {
    const legacyWorkflow = await readWorkflowYaml(projectsDir);
    if (legacyWorkflow) {
      merged = mergeConfig(merged, { workflow: legacyWorkflow });
    }
  }

  // Layer 3: project config.yaml
  if (projectName) {
    const projectDir = path.join(projectsDir, projectName);
    const projectConfig = await readConfigFile(projectDir);
    if (projectConfig) {
      merged = mergeConfig(merged, projectConfig);
    }

    // Legacy: project workflow.yaml
    if (!projectConfig?.workflow) {
      const legacyWorkflow = await readWorkflowYaml(projectDir);
      if (legacyWorkflow) {
        merged = mergeConfig(merged, { workflow: legacyWorkflow });
      }
    }
  }

  return resolve(merged);
}

/**
 * Build the default config from the built-in ROLE_REGISTRY and DEFAULT_WORKFLOW.
 */
function buildDefaultConfig(): DevClawConfig {
  const roles: Record<string, RoleOverride> = {};
  for (const [id, reg] of Object.entries(ROLE_REGISTRY)) {
    roles[id] = {
      levels: [...reg.levels],
      defaultLevel: reg.defaultLevel,
      models: { ...reg.models },
      emoji: { ...reg.emoji },
      completionResults: [...reg.completionResults],
    };
  }
  return { roles, workflow: DEFAULT_WORKFLOW };
}

/**
 * Resolve a merged DevClawConfig into a fully-typed ResolvedConfig.
 */
function resolve(config: DevClawConfig): ResolvedConfig {
  const roles: Record<string, ResolvedRoleConfig> = {};

  if (config.roles) {
    for (const [id, override] of Object.entries(config.roles)) {
      if (override === false) {
        // Disabled role — include with enabled: false for visibility
        const reg = ROLE_REGISTRY[id];
        roles[id] = {
          levels: reg ? [...reg.levels] : [],
          defaultLevel: reg?.defaultLevel ?? "",
          models: reg ? { ...reg.models } : {},
          emoji: reg ? { ...reg.emoji } : {},
          completionResults: reg ? [...reg.completionResults] : [],
          enabled: false,
        };
        continue;
      }

      const reg = ROLE_REGISTRY[id];
      roles[id] = {
        levels: override.levels ?? (reg ? [...reg.levels] : []),
        defaultLevel: override.defaultLevel ?? reg?.defaultLevel ?? "",
        models: { ...(reg?.models ?? {}), ...(override.models ?? {}) },
        emoji: { ...(reg?.emoji ?? {}), ...(override.emoji ?? {}) },
        completionResults: override.completionResults ?? (reg ? [...reg.completionResults] : []),
        enabled: true,
      };
    }
  }

  // Ensure all built-in roles exist even if not in config
  for (const [id, reg] of Object.entries(ROLE_REGISTRY)) {
    if (!roles[id]) {
      roles[id] = {
        levels: [...reg.levels],
        defaultLevel: reg.defaultLevel,
        models: { ...reg.models },
        emoji: { ...reg.emoji },
        completionResults: [...reg.completionResults],
        enabled: true,
      };
    }
  }

  const workflow: WorkflowConfig = {
    initial: config.workflow?.initial ?? DEFAULT_WORKFLOW.initial,
    states: { ...DEFAULT_WORKFLOW.states, ...config.workflow?.states },
  };

  return { roles, workflow };
}

// ---------------------------------------------------------------------------
// File reading helpers
// ---------------------------------------------------------------------------

async function readConfigFile(dir: string): Promise<DevClawConfig | null> {
  try {
    const content = await fs.readFile(path.join(dir, "config.yaml"), "utf-8");
    return YAML.parse(content) as DevClawConfig;
  } catch { /* not found */ }
  return null;
}

async function readWorkflowYaml(dir: string): Promise<Partial<WorkflowConfig> | null> {
  try {
    const content = await fs.readFile(path.join(dir, "workflow.yaml"), "utf-8");
    return YAML.parse(content) as Partial<WorkflowConfig>;
  } catch { /* not found */ }

  // Legacy JSON fallback
  try {
    const content = await fs.readFile(path.join(dir, "workflow.json"), "utf-8");
    const parsed = JSON.parse(content) as
      | Partial<WorkflowConfig>
      | { workflow?: Partial<WorkflowConfig> };
    return (parsed as any).workflow ?? parsed;
  } catch { /* not found */ }

  return null;
}
