// bot/src/commands/card-editar.ts — Reavalia artefatos de um card com novo texto

import * as fs from 'node:fs'
import * as path from 'node:path'
import { createTwoFilesPatch } from 'diff'

import type { BotConfig } from '../types'
import { JiraProvider } from '../providers/jira'
import { SlackProvider } from '../providers/slack'
import type { LLMProvider } from '../providers/llm'
import { SessionStore } from '../session/store'
import { SessionValidator } from '../session/validator'
import { WorktreeManager } from '../worktree'
import { VersionTracker } from '../versioning'
import { FileHeaderManager } from '../fileHeaders'
import { BotContext } from '../context'
import { ChannelProgress } from '../progress'
import { loadAgentPrompt } from '../agentPrompt'

export class CardEditarCommand {
  constructor(
    private readonly jira: JiraProvider,
    private readonly worktree: WorktreeManager,
    private readonly slack: SlackProvider,
    private readonly sessionStore: SessionStore,
    private readonly sessionValidator: SessionValidator,
    private readonly versionTrackerFactory: (cardId: string) => VersionTracker,
    private readonly llm: LLMProvider,
    private readonly config: BotConfig,
  ) {}

  async execute(channelId: string, userId: string, newText: string): Promise<void> {
    // 1. Resolve session by channelId
    const rawEntry = this.sessionStore.findByChannelId(channelId)
    if (!rawEntry) {
      throw new Error(`Nenhuma sessão ativa encontrada para o canal "${channelId}".`)
    }
    const entry = this.sessionValidator.validate(channelId, rawEntry.card_id)

    // 2-4. Resolve paths
    const cardId = entry.card_id
    const worktreePath = entry.worktree_path
    const docsPath = this.worktree.getDocsPath(cardId)

    // Checklist vivo dentro do canal, explicando cada passo da reavaliação.
    const progress = new ChannelProgress(
      this.slack,
      channelId,
      `✏️ *Reavaliando o card ${cardId} com o novo contexto:*`,
    )

    try {
      // 5-6. Read existing artifacts + 7-8. merge
      await progress.begin('Lendo os artefatos atuais e fundindo com o novo texto...')

      const riskMdPath = path.join(docsPath, 'risk-classification.md')
      const ideaMdPath = path.join(docsPath, 'idea.md')

      const riskParsed = FileHeaderManager.parse(riskMdPath)
      const ideaParsed = FileHeaderManager.parse(ideaMdPath)

      const riskContent = riskParsed?.content ?? ''
      const ideaContentOld = ideaParsed?.content ?? ''

      const previousContext = riskContent + '\n---\n' + ideaContentOld
      const mergedContext = await this.llm.mergeContext(previousContext, newText)

      // 9. Reprocessa os stages e versiona
      const versioning = this.versionTrackerFactory(cardId)
      const projectRoot = this.worktree.getProjectRoot()
      let ideaContentNew = ideaContentOld

      const commitRevised = async (stage: string, file: string, tag: string, content: string, status?: string): Promise<void> => {
        const filePath = path.join(docsPath, file)
        FileHeaderManager.writeWithHeader(filePath, cardId, tag, content, status)
        const version = versioning.getNext()
        await this.worktree.commitAndPush(cardId, `${stage}-revisado`, Number(version.split('.')[2]))
      }

      // risk — via sdd (determinístico); SDD_BOT_CONTEXT evita escrever em docs/.
      await progress.next('Reprocessando *risk-classification* — classificação de risco...')
      let riskOutput: string
      try {
        riskOutput = await BotContext.runSddArtifact(['risk', mergedContext, '--name', cardId], worktreePath)
      } catch {
        riskOutput = mergedContext
      }
      await commitRevised('risk-classification', 'risk-classification.md', '#risk-classification', riskOutput)

      // idea — ELABORADA via LLM com o prompt do subagent `idea` (visão rica),
      // preservando o Status existente (default /bloqueado).
      await progress.next('Reprocessando *idea* — visão de produto...')
      const ideaPrompt = loadAgentPrompt(projectRoot, 'idea')
      try {
        ideaContentNew = ideaPrompt
          ? await this.llm.generateArtifact(
              ideaPrompt,
              `Contexto consolidado do card ${cardId} (revise e reescreva a visão de produto):\n${mergedContext}`,
            )
          : await BotContext.runSddArtifact(['idea', mergedContext, '--name', cardId], worktreePath)
      } catch {
        ideaContentNew = mergedContext
      }
      const existingStatus = ideaParsed?.status ?? '/bloqueado'
      await commitRevised('idea', 'idea.md', '#idea', ideaContentNew, existingStatus)

      // 10. Update Jira description com a ideia revisada (artefato rico).
      await progress.next('Atualizando a descrição do card no Jira...')
      await this.jira.updateDescription(cardId, ideaContentNew)

      // 12. Upload updated files as attachments
      await progress.next('Enviando os artefatos atualizados como anexo...')
      const filesToUpload = [
        { path: path.join(docsPath, 'risk-classification.md'), title: 'risk-classification.md' },
        { path: path.join(docsPath, 'idea.md'), title: 'idea.md' },
      ]
      await this.slack.postFiles(channelId, filesToUpload)

      await progress.finish('Reavaliação concluída. Veja o resumo das mudanças abaixo.')

      // 13. Post diff summary (first 20 lines of idea.md)
      const oldLines = ideaContentOld.split('\n').slice(0, 20).join('\n')
      const newLines = ideaContentNew.split('\n').slice(0, 20).join('\n')
      const diffText = createTwoFilesPatch('idea.md (antes)', 'idea.md (depois)', oldLines, newLines)

      const diffBlock = diffText.length > 0
        ? `\`\`\`diff\n${diffText}\n\`\`\``
        : '_Sem diferenças detectadas nas primeiras 20 linhas._'

      await this.slack.postMessage(
        channelId,
        `*Resumo das alterações em \`idea.md\` (primeiras 20 linhas):*\n${diffBlock}`,
      )
    } catch (err: unknown) {
      const msg = err instanceof Error ? err.message : String(err)
      await progress.fail(msg).catch(() => undefined)
      throw err
    }
  }
}
