/**
 * Накопитель отчёта по e2e-сценарию. Markdown с секциями step-by-step.
 * Каждый step фиксирует API/UI checks, статус (pass/fail/warn), время,
 * и в конце runner добавляет summary + категоризованные рекомендации.
 */
import { writeFileSync, mkdirSync } from 'node:fs'
import { dirname } from 'node:path'

export type StepStatus = 'pass' | 'fail' | 'warn' | 'skip'

export interface CheckResult {
  kind: 'api' | 'ui' | 'db'
  description: string
  ok: boolean
  detail?: string
}

export interface Step {
  id: string
  title: string
  status: StepStatus
  checks: CheckResult[]
  durationMs: number
  notes: string[]
  screenshot?: string
}

export interface Bug {
  step: string
  severity: 'critical' | 'high' | 'medium' | 'low'
  title: string
  detail: string
  fix?: string
}

export class Report {
  scenario: string
  startedAt = new Date()
  steps: Step[] = []
  bugs: Bug[] = []
  uxNotes: string[] = []
  logicGaps: string[] = []
  perfNotes: string[] = []

  constructor(scenario: string) {
    this.scenario = scenario
  }

  startStep(id: string, title: string): Step {
    const step: Step = { id, title, status: 'pass', checks: [], durationMs: 0, notes: [] }
    this.steps.push(step)
    return step
  }

  finishStep(step: Step, t0: number) {
    step.durationMs = Date.now() - t0
    if (step.checks.some((c) => !c.ok)) step.status = 'fail'
  }

  bug(b: Bug) { this.bugs.push(b) }
  ux(s: string) { this.uxNotes.push(s) }
  gap(s: string) { this.logicGaps.push(s) }
  perf(s: string) { this.perfNotes.push(s) }

  finalize(filePath: string) {
    mkdirSync(dirname(filePath), { recursive: true })
    writeFileSync(filePath, this.toMarkdown(), 'utf8')
  }

  private icon(s: StepStatus): string {
    switch (s) {
      case 'pass': return '✓'
      case 'fail': return '✗'
      case 'warn': return '⚠'
      case 'skip': return '◯'
    }
  }

  toMarkdown(): string {
    const passed = this.steps.filter((s) => s.status === 'pass').length
    const failed = this.steps.filter((s) => s.status === 'fail').length
    const warns = this.steps.filter((s) => s.status === 'warn').length
    const skipped = this.steps.filter((s) => s.status === 'skip').length

    const lines: string[] = []
    lines.push(`# E2E report: ${this.scenario}`)
    lines.push('')
    lines.push(`Запущен: ${this.startedAt.toISOString()}`)
    lines.push(`Длительность: ${(this.steps.reduce((a, s) => a + s.durationMs, 0) / 1000).toFixed(1)}с`)
    lines.push('')
    lines.push(`**Итог:** ${passed} ✓ / ${failed} ✗ / ${warns} ⚠ / ${skipped} ◯ (всего ${this.steps.length})`)
    lines.push('')

    for (const step of this.steps) {
      lines.push(`## ${this.icon(step.status)} Step ${step.id}: ${step.title}`)
      lines.push('')
      lines.push(`Длительность: ${step.durationMs}мс`)
      if (step.checks.length > 0) {
        lines.push('')
        lines.push('| Тип | Проверка | Результат |')
        lines.push('|---|---|---|')
        for (const c of step.checks) {
          const cell = c.detail ? `${c.detail.replace(/\|/g, '\\|').slice(0, 200)}` : ''
          lines.push(`| ${c.kind} | ${c.description} | ${c.ok ? '✓' : '✗'} ${cell} |`)
        }
      }
      if (step.notes.length > 0) {
        lines.push('')
        for (const n of step.notes) lines.push(`> ${n}`)
      }
      if (step.screenshot) {
        lines.push('')
        lines.push(`Скриншот: \`${step.screenshot}\``)
      }
      lines.push('')
    }

    lines.push('## Summary')
    lines.push('')
    lines.push(`- Passed: ${passed}`)
    lines.push(`- Failed: ${failed}`)
    lines.push(`- Warnings: ${warns}`)
    lines.push(`- Skipped: ${skipped}`)
    lines.push('')

    if (this.bugs.length > 0) {
      lines.push('## Critical bugs')
      lines.push('')
      const order: Bug['severity'][] = ['critical', 'high', 'medium', 'low']
      for (const sev of order) {
        const list = this.bugs.filter((b) => b.severity === sev)
        if (list.length === 0) continue
        lines.push(`### ${sev.toUpperCase()}`)
        lines.push('')
        for (const b of list) {
          lines.push(`- **[${b.step}] ${b.title}**`)
          lines.push(`  - ${b.detail}`)
          if (b.fix) lines.push(`  - Fix: ${b.fix}`)
        }
        lines.push('')
      }
    } else {
      lines.push('## Critical bugs')
      lines.push('')
      lines.push('Нет.')
      lines.push('')
    }

    if (this.uxNotes.length > 0) {
      lines.push('## UX recommendations')
      lines.push('')
      for (const n of this.uxNotes) lines.push(`- ${n}`)
      lines.push('')
    }

    if (this.logicGaps.length > 0) {
      lines.push('## Logic gaps')
      lines.push('')
      for (const n of this.logicGaps) lines.push(`- ${n}`)
      lines.push('')
    }

    if (this.perfNotes.length > 0) {
      lines.push('## Performance observations')
      lines.push('')
      for (const n of this.perfNotes) lines.push(`- ${n}`)
      lines.push('')
    }

    return lines.join('\n')
  }
}
