// bot/src/index.ts — Ponto de entrada do SDD Slack Bot (Bolt + Socket Mode)

import path from 'path'
import { App } from '@slack/bolt'
import { Config, loadConfig } from './config'
import { createLLMProvider } from './providers/llm/index'
import { SlackProvider } from './providers/slack'
import { JiraProvider } from './providers/jira'
import { BitbucketProvider } from './providers/bitbucket'
import { GitHubProvider } from './providers/github'
import { startGitHubWebhookReceiver } from './providers/githubWebhookReceiver'
import type { RepoProvider, WorkTrackerProvider } from './providers/contracts'
import { SessionStore } from './session/store'
import { SessionValidator } from './session/validator'
import { WorktreeManager } from './worktree'
import { VersionTracker } from './versioning'
import { registerBotCommand } from './commands/bot'

async function main(): Promise<void> {
  // ── 1. Configuração ──────────────────────────────────────────────────────────

  const configInstance = Config.getInstance()
  const config = loadConfig()

  // ── 2. Raiz do projeto ───────────────────────────────────────────────────────

  const projectRoot = process.env['SDD_BOT_ROOT']
    ? path.resolve(process.env['SDD_BOT_ROOT'])
    : configInstance.getProjectRoot()

  // ── 3. Bolt App ──────────────────────────────────────────────────────────────

  const app = new App({
    socketMode: true,
    token: config.slack.bot_token,
    appToken: config.slack.app_token,
  })

  // ── 4. Providers e stores ────────────────────────────────────────────────────

  const llm = await createLLMProvider(config.llm)

  const slackProvider = new SlackProvider(config.slack, app)
  const workTrackerProvider = createWorkTrackerProvider(config, projectRoot)
  const repoProvider = createRepoProvider(config, projectRoot)

  const sessionsPath = path.join(projectRoot, '.sdd', 'bot', 'sessions.json')
  const sessionStore = SessionStore.getInstance(sessionsPath)
  const sessionValidator = new SessionValidator(sessionStore)

  const worktreeManager = new WorktreeManager(projectRoot)

  const versionTrackerFactory = (cardId: string): VersionTracker =>
    VersionTracker.getInstance(cardId, projectRoot)

  // ── 6. Helper: postar no canal de logs sem lançar exceção ────────────────────

  const postToLogs = async (text: string): Promise<void> => {
    try {
      const logsChannel = slackProvider.getLogsChannel()
      await slackProvider.postMessage(logsChannel, text)
    } catch {
      // silencia falha de log para não causar loop
    }
  }

  startGitHubWebhookReceiver(config.github, async (action, event) => {
    await postToLogs(`:satellite: GitHub webhook ${event}: ${action.type}`)
  })

  // ── 7. Comando /bot ──────────────────────────────────────────────────────────

  registerBotCommand(app, { llm, workTrackerProvider, repoProvider, projectRoot })

  // ── 8. Handler de erros global ───────────────────────────────────────────────

  app.error(async (error) => {
    console.error('[sdd-bot] Erro não tratado pelo Bolt:', error)
    await postToLogs(`:rotating_light: Erro global do bot: ${error.message}`)
  })

  // ── 10. Start ────────────────────────────────────────────────────────────────

  await app.start()
  console.log(`Bot SDD iniciado · Sessão: ${config.slack.session_name}`)
}

function selectedWorkTracker(config: ReturnType<typeof loadConfig>): 'jira' | 'github' {
  return config.integrations?.work_tracker ?? (config.jira ? 'jira' : config.github ? 'github' : 'jira')
}

function selectedRepo(config: ReturnType<typeof loadConfig>): 'bitbucket' | 'github' | 'git' {
  return config.integrations?.repo ?? (config.bitbucket ? 'bitbucket' : config.github ? 'github' : 'bitbucket')
}

function createWorkTrackerProvider(
  config: ReturnType<typeof loadConfig>,
  projectRoot: string,
): WorkTrackerProvider {
  if (selectedWorkTracker(config) === 'github') {
    if (!config.github) throw new Error('[sdd-bot] github não configurado')
    return new GitHubProvider(config.github, projectRoot)
  }
  if (!config.jira) throw new Error('[sdd-bot] jira não configurado')
  return new JiraProvider(config.jira)
}

function createRepoProvider(
  config: ReturnType<typeof loadConfig>,
  projectRoot: string,
): RepoProvider | undefined {
  const repo = selectedRepo(config)
  if (repo === 'github') {
    if (!config.github) throw new Error('[sdd-bot] github não configurado')
    return new GitHubProvider(config.github, projectRoot)
  }
  if (repo === 'bitbucket') {
    if (!config.bitbucket) throw new Error('[sdd-bot] bitbucket não configurado')
    return new BitbucketProvider(config.bitbucket, projectRoot)
  }
  return undefined
}

main().catch((err: unknown) => {
  const msg = err instanceof Error ? err.message : String(err)
  console.error(`[sdd-bot] Falha fatal na inicialização: ${msg}`)
  process.exit(1)
})
