import { detectDbContexts, findStartupProject, hasDotnetProject } from '../lib/detect-dbcontexts.js';
import { listMigrationsJson, dotnetAvailable, dotnetEfAvailable } from '../lib/ef-runner.js';
import type { AssemblyListing, ContextListing, ListResult, ListSpec } from './types.js';

export async function execute(spec: ListSpec): Promise<ListResult> {
  const warnings: string[] = [];

  if (!(await hasDotnetProject(spec.cwd))) {
    return {
      success: true,
      cwd: spec.cwd,
      kind: 'unknown',
      contexts: [],
      warnings: ['No .csproj found in worktree — nothing to list.'],
    };
  }

  if (!(await dotnetAvailable())) {
    return {
      success: false,
      cwd: spec.cwd,
      kind: 'unknown',
      contexts: [],
      warnings,
      error: 'dotnet CLI is not available on PATH',
    };
  }

  if (!(await dotnetEfAvailable())) {
    warnings.push('dotnet-ef tool is not installed globally — run: dotnet tool install --global dotnet-ef');
  }

  const detection = await detectDbContexts(spec.cwd);
  const startupProject = await findStartupProject(spec.cwd);

  const out: ContextListing[] = [];

  for (const ctx of detection.contexts) {
    if (spec.contextName && ctx.name !== spec.contextName) continue;

    const assemblies: AssemblyListing[] = [];
    for (const asm of ctx.assemblies) {
      if (spec.assembly && asm.assemblyName !== spec.assembly) continue;

      const extraEnv = asm.provider
        ? { STUDIO_DESIGN_PROVIDER: capitalize(asm.provider) }
        : undefined;

      const result = await listMigrationsJson(spec.cwd, {
        context: ctx.name,
        projectPath: asm.csprojPath,
        startupProjectPath: startupProject ?? undefined,
        extraEnv,
      });

      assemblies.push({
        assemblyName: asm.assemblyName,
        csprojPath: asm.csprojPath,
        migrationsDir: asm.migrationsDir,
        provider: asm.provider,
        version: asm.version,
        migrations: result.migrations,
        error: result.success ? undefined : result.error,
      });
    }

    out.push({ contextName: ctx.name, assemblies });
  }

  return {
    success: true,
    cwd: detection.cwd,
    kind: detection.kind,
    contexts: out,
    warnings,
  };
}

function capitalize(s: string): string {
  if (!s) return s;
  if (s.toLowerCase() === 'sqlserver') return 'SqlServer';
  return s.charAt(0).toUpperCase() + s.slice(1);
}
