// bot/src/commands/bot-criar.ts — Handles /sdd bot-criar <description>
// Sent in the <prefix>-comandos channel.
//
// Flow:
//   A) Jira: create card + block comment
//   B) Worktree: create branch, push, scaffold docs
//   C) Slack: create private channel, invite members, persist session
//   D) SDD CLI: run risk-classification + idea stages, write artifacts, commit
//   E) Deliver: upload files, post summary

import path from 'node:path'
import { randomUUID } from 'node:crypto'
import type { BotConfig } from '../types'
import type { JiraProvider } from '../providers/jira'
import type { SlackProvider } from '../providers/slack'
import type { BitbucketProvider } from '../providers/bitbucket'
import type { LLMProvider } from '../providers/llm/index'
import { SessionStore } from '../session/store'
import { WorktreeManager } from '../worktree'
import { VersionTracker } from '../versioning'
import { FileHeaderManager } from '../fileHeaders'
import { BotContext } from '../context'
import { CommandProgress, ChannelProgress, type RespondFn } from '../progress'
import { loadAgentPrompt } from '../agentPrompt'

type VersionTrackerFactory = (cardId: string) => VersionTracker

// Explicação curta de cada etapa, exibida ao usuário durante a geração.
const STAGE_INFO: Record<string, { label: string; explain: string }> = {
  'risk-classification': {
    label: 'risk-classification',
    explain: 'classificação de risco da feature (nível e checkpoints)',
  },
  idea: { label: 'idea', explain: 'visão de produto: problema, valor e escopo' },
}

export class BotCriarCommand {
  constructor(
    private readonly jira: JiraProvider,
    private readonly worktree: WorktreeManager,
    private readonly slack: SlackProvider,
    private readonly bitbucket: BitbucketProvider,
    private readonly llm: LLMProvider,
    private readonly sessionStore: SessionStore,
    private readonly versionTrackerFactory: VersionTrackerFactory,
    private readonly config: BotConfig,
  ) {}

  async execute(
    userId: string,
    description: string,
    respondFn: RespondFn,
  ): Promise<void> {
    let cardId: string | undefined
    let channelId: string | undefined

    // Checklist vivo no canal de comandos: o usuário vê cada passo (🔄 → ✅)
    // em tempo real, em vez de ficar sem informação até o canal ser criado.
    const progress = new CommandProgress(respondFn, '*bot-criar* em andamento:')

    const postError = async (err: unknown, context: string): Promise<void> => {
      const msg = err instanceof Error ? err.message : String(err)
      const stack = err instanceof Error ? err.stack ?? '' : ''
      console.error(`[bot-criar] ${context}: ${msg}\n${stack}`)
      // Marca o passo atual como falho no checklist do canal de comandos.
      await progress.fail(`Erro em ${context}: ${msg}`).catch(() => undefined)
      // E também avisa no canal privado, se já existir.
      if (channelId) {
        await this.slack
          .postMessage(channelId, `:x: Erro em *${context}*: ${msg}`)
          .catch(() => undefined)
      }
    }

    try {
      // ── STEP A — JIRA ──────────────────────────────────────────────────────
      await progress.begin('Criando o card no Jira (coluna Ideia/Backlog)...')

      const title = await this.llm.generateTitle(description)
      cardId = await this.jira.createCard(title, description)
      await this.jira.addComment(cardId, '/bloqueado')

      // ── STEP B — WORKTREE ──────────────────────────────────────────────────
      await progress.next(
        `Card *${cardId}* criado · Preparando o worktree (branch a partir de homolog)...`,
      )

      const worktreePath = await this.worktree.create(cardId)
      await this.bitbucket.pushBranch(cardId)
      await this.worktree.createDocStructure(cardId)

      // ── STEP C — SLACK CHANNEL ─────────────────────────────────────────────
      await progress.next('Worktree pronto · Criando o canal privado da sessão...')

      channelId = await this.slack.createPrivateChannel(cardId)

      const adminIds = await this.slack.getAdminUserIds()
      const memberIds = [userId, ...adminIds]
      await this.slack.addMembers(channelId, memberIds)

      const sessionEntry = {
        slack_channel_id: channelId,
        worktree_path: worktreePath,
        agent_session_id: randomUUID(),
        owner_user_id: userId,
        card_id: cardId,
        status: 'em_elaboracao' as const,
        created_at: new Date().toISOString(),
      }
      this.sessionStore.set(cardId, sessionEntry)

      await progress.next(
        `Canal <#${channelId}> criado · Gerando os artefatos (acompanhe lá dentro)...`,
      )

      // Mensagem de boas-vindas explicativa no canal privado.
      await this.slack.postMessage(
        channelId,
        [
          `👋 *Canal do card ${cardId}*`,
          'Aqui você acompanha a geração dos artefatos e pode usar:',
          '• `/sdd card-editar <texto>` — revisar ideia/risk com novo contexto',
          '• `/aprovado` — liberar as próximas etapas do fluxo',
        ].join('\n'),
      )

      // ── STEP D — SDD CLI ───────────────────────────────────────────────────

      const versioning = this.versionTrackerFactory(cardId)
      let ideaContent = ''

      // Checklist vivo dentro do canal privado, com explicação de cada etapa.
      const genProgress = new ChannelProgress(
        this.slack,
        channelId,
        '⚙️ *Gerando artefatos da etapa de ideia:*',
      )

      const projectRoot = this.worktree.getProjectRoot()
      const commitStage = async (stage: string, fileName: string, content: string, status?: string): Promise<void> => {
        const filePath = path.join(worktreePath, 'docs', cardId!, fileName)
        FileHeaderManager.writeWithHeader(filePath, cardId!, `#${stage}`, content, status)
        const versionString = versioning.getNext()
        const versionNumber = parseInt(versionString.split('.').pop() ?? '1', 10)
        await this.worktree.commitAndPush(cardId!, stage, versionNumber)
      }

      // 1) risk-classification — via `sdd risk` (classificação determinística).
      //    Com SDD_BOT_CONTEXT, o sdd devolve o markdown e NÃO escreve em docs/.
      const riskInfo = STAGE_INFO['risk-classification']
      await genProgress.begin(`Gerando *${riskInfo.label}* — ${riskInfo.explain}...`)
      const riskOutput = await BotContext.runSddArtifact(
        ['risk', description, '--name', cardId, '--root', worktreePath],
        worktreePath,
      )
      await commitStage('risk-classification', 'risk-classification.md', riskOutput)

      // 2) idea — ELABORADA via LLM usando o prompt do subagent `idea`, para gerar
      //    a visão de produto rica (problema, valor, jornada, MVP, riscos, EARS),
      //    em vez do esqueleto que o `sdd idea` (CLI) devolve.
      const ideaInfo = STAGE_INFO['idea']
      await genProgress.next(`Gerando *${ideaInfo.label}* — ${ideaInfo.explain}...`)
      const ideaPrompt = loadAgentPrompt(projectRoot, 'idea')
      if (ideaPrompt) {
        ideaContent = await this.llm.generateArtifact(
          ideaPrompt,
          `Descrição da feature (projeto/card ${cardId}):\n${description}`,
        )
      } else {
        // Fallback: sem o prompt do subagent, usa o esqueleto do sdd.
        ideaContent = await BotContext.runSddArtifact(
          ['idea', description, '--name', cardId, '--root', worktreePath],
          worktreePath,
        )
      }
      await commitStage('idea', 'idea.md', ideaContent, '/bloqueado')

      await genProgress.finish('Artefatos gerados e versionados no worktree.')

      // Atualiza a descrição do card no Jira com a ideia gerada, deixando o card
      // autocontido para quem acompanha pelo Jira. Falha aqui não aborta o fluxo.
      if (ideaContent.trim().length > 0) {
        await this.slack.postMessage(channelId, '🔄 Atualizando a descrição do card no Jira com a ideia...')
        try {
          await this.jira.updateDescription(cardId, ideaContent)
          await this.slack.postMessage(channelId, '✅ Descrição do card atualizada no Jira.')
        } catch (err: unknown) {
          const msg = err instanceof Error ? err.message : String(err)
          await this.slack.postMessage(
            channelId,
            `⚠️ Artefatos gerados, mas não consegui atualizar a descrição no Jira: ${msg}`,
          )
        }
      }

      // ── STEP E — DELIVER ───────────────────────────────────────────────────
      await this.slack.postMessage(channelId, '🔄 Enviando os artefatos como anexo...')

      const riskFilePath = path.join(worktreePath, 'docs', cardId, 'risk-classification.md')
      const ideaFilePath = path.join(worktreePath, 'docs', cardId, 'idea.md')

      await this.slack.postFiles(channelId, [
        { path: riskFilePath, title: 'risk-classification.md' },
        { path: ideaFilePath, title: 'idea.md' },
      ])

      await this.slack.postMessage(
        channelId,
        [
          '📎 *Artefatos prontos!* Anexei `risk-classification.md` e `idea.md` acima.',
          'Próximos passos:',
          '• `/sdd card-editar <texto>` — revisar com novo contexto',
          '• `/aprovado` — liberar as próximas etapas',
        ].join('\n'),
      )

      // Finaliza o checklist do canal de comandos com link para o canal.
      await progress.finish(
        `✅ *Tudo pronto!* Card *${cardId}* criado e artefatos gerados. ` +
          `Acesse o canal <#${channelId}> para ver os documentos e continuar.`,
      )
    } catch (err: unknown) {
      const context = cardId ? `bot-criar [${cardId}]` : 'bot-criar'
      await postError(err, context)
    }
  }
}
