/**
 * E2E-runner. Принимает имя сценария, читает YAML, выполняет preconditions
 * и steps, в конце пишет markdown-отчёт.
 *
 * Запуск: pnpm tsx runner.ts <scenario> [--api-only]
 *
 * Сценарий описывает мета-информацию + список step-id. Логика каждого
 * step-а — в `scenarios/<name>.steps.ts`. Это гибрид DSL + код: YAML
 * декларативный, но конкретные проверки (Playwright assertions / axios calls)
 * хранятся как функции, потому что для всех 12 шагов full-cycle описать
 * сложные UI-сценарии чисто декларативно неоправданно.
 */
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { load as parseYaml } from 'js-yaml'
import { Report } from './lib/report.js'
import { resetTenantData } from './lib/db.js'
import { login } from './lib/api.js'

interface Scenario {
  name: string
  description?: string
  preconditions?: { reset_db?: boolean; smoke_login_super_admin?: boolean }
  steps: { id: string; title: string }[]
}

async function main() {
  const args = process.argv.slice(2)
  const name = args.find((a) => !a.startsWith('--'))
  if (!name) {
    console.error('Usage: tsx runner.ts <scenario> [--api-only]')
    process.exit(2)
  }
  const apiOnly = args.includes('--api-only')

  const scenarioPath = resolve(import.meta.dirname, 'scenarios', `${name}.yml`)
  const scenario = parseYaml(readFileSync(scenarioPath, 'utf8')) as Scenario
  const stepsModule = await import(resolve(import.meta.dirname, 'scenarios', `${name}.steps.ts`))

  const report = new Report(scenario.name)

  // Preconditions
  if (scenario.preconditions?.reset_db) {
    console.error('[preflight] resetting tenant data...')
    resetTenantData()
  }
  if (scenario.preconditions?.smoke_login_super_admin !== false) {
    try {
      const sa = await login('admin@food-market.local', 'Admin12345!')
      if (!sa.roles.includes('SuperAdmin')) {
        throw new Error(`SuperAdmin not in roles: ${sa.roles}`)
      }
      console.error(`[preflight] SuperAdmin login OK (sub=${sa.email})`)
    } catch (e) {
      console.error('[preflight] SuperAdmin login FAILED — abort', e)
      process.exit(3)
    }
  }

  // Контекст пробрасываем между steps — accumulator для ID'ов созданных сущностей.
  const ctx: Record<string, unknown> = { apiOnly }

  for (const stepDecl of scenario.steps) {
    const handler = stepsModule[stepDecl.id]
    if (typeof handler !== 'function') {
      const step = report.startStep(stepDecl.id, stepDecl.title)
      step.status = 'skip'
      step.notes.push(`Handler ${stepDecl.id} не найден в ${name}.steps.ts`)
      console.error(`[${stepDecl.id}] SKIP (no handler)`)
      continue
    }
    const t0 = Date.now()
    const step = report.startStep(stepDecl.id, stepDecl.title)
    console.error(`[${stepDecl.id}] ${stepDecl.title}...`)
    try {
      await handler({ ctx, step, report })
    } catch (e) {
      step.status = 'fail'
      step.notes.push(`Exception: ${(e as Error).message}`)
      console.error(`[${stepDecl.id}] FAIL: ${(e as Error).message}`)
    }
    report.finishStep(step, t0)
    console.error(`[${stepDecl.id}] ${step.status} (${step.durationMs}ms)`)
  }

  const ts = new Date().toISOString().replace(/[:.]/g, '-')
  const reportPath = resolve(import.meta.dirname, 'reports', `${name}-${ts}.md`)
  report.finalize(reportPath)
  console.error(`[done] report → ${reportPath}`)
  console.error(report.toMarkdown().split('\n').slice(0, 20).join('\n'))
}

main().catch((e) => { console.error(e); process.exit(1) })
