// Idempotent insert van één milestone (PBI + stories + tasks) uit de backlog.
//
// Gebruik:
//   npm run db:insert-milestone -- M8                       # standaard product SCRUM4ME
//   npm run db:insert-milestone -- M8 --product SCRUM4ME    # idem
//   npm run db:insert-milestone -- M8 --dry-run             # niets schrijven, alleen tonen
//
// Bron: docs/scrum4me-backlog.md (gecommit, single source of truth).
// Tweede keer draaien is veilig: bestaande PBIs/stories/tasks worden niet
// gedupliceerd. Sprint-toewijzing doe je apart via Sprint Planning in de UI.

import { PrismaClient } from '@prisma/client'
import * as dotenv from 'dotenv'
import * as path from 'path'
import { Pool } from 'pg'
import { PrismaPg } from '@prisma/adapter-pg'
import { loadBacklog } from '../prisma/seed-data/parse-backlog'

const root = path.resolve(__dirname, '..')
dotenv.config({ path: path.join(root, '.env.local'), override: true })
dotenv.config({ path: path.join(root, '.env') })

interface Args {
  milestoneKey: string
  productCode: string
  dryRun: boolean
}

function parseArgs(argv: string[]): Args {
  const positional: string[] = []
  let productCode = 'SCRUM4ME'
  let dryRun = false

  for (let i = 0; i < argv.length; i++) {
    const a = argv[i]
    if (a === '--product') productCode = argv[++i] ?? ''
    else if (a === '--dry-run') dryRun = true
    else if (a.startsWith('--')) throw new Error(`Unknown flag: ${a}`)
    else positional.push(a)
  }

  if (positional.length !== 1) {
    throw new Error('Usage: insert-milestone <milestone-key> [--product CODE] [--dry-run]')
  }
  const milestoneKey = positional[0]
  if (!/^M[\d.]+$/.test(milestoneKey)) {
    throw new Error(`Invalid milestone key: ${milestoneKey} (expected M0, M3.5, M8, ...)`)
  }
  if (!productCode) throw new Error('--product cannot be empty')

  return { milestoneKey, productCode, dryRun }
}

async function main() {
  const args = parseArgs(process.argv.slice(2))
  const url = process.env.DATABASE_URL
  if (!url) throw new Error('DATABASE_URL is not set. Check .env.local')

  const pool = new Pool({ connectionString: url })
  const adapter = new PrismaPg(pool)
  const prisma = new PrismaClient({ adapter })

  try {
    const milestones = await loadBacklog(root, { strict: false })
    const ms = milestones.find((m) => m.key === args.milestoneKey)
    if (!ms) {
      throw new Error(
        `Milestone ${args.milestoneKey} not found in docs/scrum4me-backlog.md (parsed: ${milestones.map((m) => m.key).join(', ')})`,
      )
    }

    const product = await prisma.product.findFirst({
      where: { code: args.productCode, archived: false },
      select: { id: true, name: true, code: true },
    })
    if (!product) throw new Error(`Product with code "${args.productCode}" not found`)

    console.log(
      `Inserting ${ms.key} (${ms.title}) into product ${product.code} — ${ms.stories.length} stories${args.dryRun ? ' [DRY RUN]' : ''}`,
    )

    let pbiCreated = 0
    let storiesCreated = 0
    let storiesUpdated = 0
    let tasksCreated = 0

    // PBI upsert
    const existingPbi = await prisma.pbi.findFirst({
      where: { product_id: product.id, code: ms.key },
      select: { id: true },
    })

    let pbiId: string
    if (existingPbi) {
      pbiId = existingPbi.id
    } else if (args.dryRun) {
      pbiId = '<new-pbi-id>'
      pbiCreated = 1
    } else {
      const maxPbi = await prisma.pbi.aggregate({
        where: { product_id: product.id },
        _max: { sort_order: true },
      })
      const nextSort = (maxPbi._max.sort_order ?? 0) + 1
      const created = await prisma.pbi.create({
        data: {
          product_id: product.id,
          code: ms.key,
          title: ms.title,
          description: ms.goal,
          priority: ms.priority,
          sort_order: nextSort,
        },
        select: { id: true },
      })
      pbiId = created.id
      pbiCreated = 1
    }

    // Stories + tasks
    for (const s of ms.stories) {
      const existingStory = await prisma.story.findFirst({
        where: { product_id: product.id, code: s.ref },
        select: { id: true, _count: { select: { tasks: true } } },
      })

      const storyData = {
        pbi_id: pbiId,
        product_id: product.id,
        code: s.ref,
        title: s.title,
        description: s.tasks.map((t) => t.title).join('; '),
        acceptance_criteria: s.acceptance_criteria,
        priority: ms.priority,
        sort_order: s.sort_order,
        status: s.status === 'DONE' ? 'DONE' as const : 'OPEN' as const,
      }

      let storyId: string
      let hadTasks = false
      if (existingStory) {
        hadTasks = existingStory._count.tasks > 0
        storyId = existingStory.id
        if (!args.dryRun) {
          await prisma.story.update({
            where: { id: existingStory.id },
            data: storyData,
          })
        }
        storiesUpdated++
      } else if (args.dryRun) {
        storyId = `<new-story-${s.ref}>`
        storiesCreated++
      } else {
        const created = await prisma.story.create({
          data: storyData,
          select: { id: true },
        })
        storyId = created.id
        storiesCreated++
      }

      // Tasks: alleen als de story op dit moment 0 tasks had
      if (!hadTasks && s.tasks.length > 0) {
        if (!args.dryRun) {
          const allTasks = await prisma.task.findMany({
            where: { product_id: product.id },
            select: { code: true },
          })
          const maxN = allTasks.reduce((m, t) => {
            const match = /^T-(\d+)$/.exec(t.code)
            return match ? Math.max(m, Number(match[1])) : m
          }, 0)
          await prisma.task.createMany({
            data: s.tasks.map((t, i) => ({
              story_id: storyId,
              product_id: product.id,
              code: `T-${maxN + i + 1}`,
              title: t.title,
              description: t.description || null,
              priority: ms.priority,
              sort_order: t.sort_order,
              status: s.status === 'DONE' ? 'DONE' as const : 'TO_DO' as const,
            })),
          })
        }
        tasksCreated += s.tasks.length
      }
    }

    console.log(
      `Result: PBI ${pbiCreated ? 'created' : 'reused'}, stories ${storiesCreated} created / ${storiesUpdated} updated, tasks ${tasksCreated} created${args.dryRun ? ' [DRY RUN — niets geschreven]' : ''}`,
    )
    if (storiesCreated > 0 || pbiCreated > 0) {
      console.log(
        `Tip: stories staan nog niet in een sprint. Plan ze via Sprint Planning in de UI als je ze in de Solo Paneel wil zien.`,
      )
    }
  } finally {
    await prisma.$disconnect()
    await pool.end()
  }
}

main().catch((err) => {
  console.error('insert-milestone failed:', err.message)
  process.exit(1)
})
