import { execSync } from 'node:child_process'
import path, { resolve } from 'node:path'
import { findFiles } from '../../../../../lib/fs.js'
import { ensureSqlObjectsInMigration } from '../../../../../lib/sql-objects.js'
import type { ScaffoldMigrationInput } from './types.js'

export interface ScaffoldMigrationResult {
  success: boolean
  output: string
  /** SQL objects (schema.name) frozen into the generated migration from SqlObjects/. */
  sqlObjectsInlined: string[]
}

export async function execute(input: ScaffoldMigrationInput): Promise<ScaffoldMigrationResult> {
  const projectRoot = resolve(input.projectPath)
  const cmd = `dotnet ef migrations add ${input.name} --project src/${input.appCode}.Infrastructure --startup-project src/${input.appCode}.Api`

  let output: string
  try {
    output = execSync(cmd, { cwd: projectRoot, encoding: 'utf-8', timeout: 120_000 }).slice(0, 2000)
  } catch (err: any) {
    return {
      success: false,
      output: ((err.stdout ?? '') + '\n' + (err.stderr ?? '')).slice(0, 2000),
      sqlObjectsInlined: [],
    }
  }

  // Freeze any new/changed SQL objects (functions/views/procs under SqlObjects/**)
  // into the migration EF just generated. EF never emits raw SQL, so without this
  // a `dotnet ef database update` that doesn't boot the app won't deploy them.
  // Same shared helper as `/efcore create` + `/efcore squash`.
  let sqlObjectsInlined: string[] = []
  try {
    const projectDir = path.join(projectRoot, 'src', `${input.appCode}.Infrastructure`)
    const generated = (await findFiles(`**/*_${input.name}.cs`, { cwd: projectDir }))
      .filter((f) => !f.endsWith('.Designer.cs'))
      .sort((a, b) => b.localeCompare(a))
    if (generated.length > 0) {
      const ensure = await ensureSqlObjectsInMigration({
        projectDir,
        migrationsDir: path.dirname(generated[0]),
        migrationName: input.name,
      })
      sqlObjectsInlined = ensure.inlined
      if (ensure.injected) {
        output += `\n\nInlined ${ensure.inlined.length} SQL object(s) into the migration so \`database update\` deploys them: ${ensure.inlined.join(', ')}`
      }
    }
  } catch (e) {
    output += `\n\n(SQL-object inlining skipped: ${(e as Error).message})`
  }

  return { success: true, output, sqlObjectsInlined }
}
