import { jsonResponse, errorResponse, corsHeaders } from '../utils/cors'
import { existsSync, readdirSync, readFileSync, statSync } from 'fs'
import { join } from 'path'
import { homedir } from 'os'
import { spawn } from 'child_process'
import { WORKING_DIR } from '../config'

// Agent transcript directories
const AGENT_DIRS: Record<string, string> = {
  ejecutor: join(WORKING_DIR, '.claude-ejecutor', 'projects'),
  nucleo000: join(WORKING_DIR, '.claude-nucleo000', 'projects'),
  claude: join(homedir(), '.claude', 'projects')
}

// Agent CLI commands (these .cmd wrappers handle CLAUDE_CONFIG_DIR + cd)
const AGENT_COMMANDS: Record<string, string> = {
  ejecutor: 'ejecutor',
  nucleo000: 'nucleo000',
  claude: 'claude'
}

// Track running processes per session to prevent concurrent sends
const runningProcesses = new Map<string, { pid: number; kill: () => void }>()

// Broadcast callback — set by sync-server to push WebSocket messages
let broadcastFn: ((msg: string) => void) | null = null

export function setTranscriptDebugBroadcast(fn: (msg: string) => void) {
  broadcastFn = fn
}

// Project hash for this project
const PROJECT_HASH = 'C--Users-jodar-agent-ui'

function getProjectDir(agent: string): string | null {
  const baseDir = AGENT_DIRS[agent]
  if (!baseDir || !existsSync(baseDir)) return null

  // Try exact project hash first
  const exact = join(baseDir, PROJECT_HASH)
  if (existsSync(exact)) return exact

  // Fallback: first directory
  const dirs = readdirSync(baseDir)
  return dirs.length > 0 ? join(baseDir, dirs[0]) : null
}

function extractFirstUserMessage(filePath: string): string {
  try {
    const content = readFileSync(filePath, 'utf-8')
    const lines = content.split('\n')
    for (const line of lines) {
      if (!line.trim()) continue
      try {
        const obj = JSON.parse(line)
        if (obj.type === 'user' && obj.message) {
          const c = obj.message.content
          if (typeof c === 'string') return c.slice(0, 120)
          if (Array.isArray(c)) {
            const textBlock = c.find((b: any) => b.type === 'text' && b.text?.trim())
            if (textBlock) return textBlock.text.slice(0, 120)
          }
        }
      } catch {}
    }
  } catch {}
  return ''
}

export function handleTranscriptDebugSessions(url: URL): Response {
  const agent = url.searchParams.get('agent') || 'ejecutor'
  const projectDir = getProjectDir(agent)
  if (!projectDir || !existsSync(projectDir)) {
    return jsonResponse([])
  }

  const files = readdirSync(projectDir)
    .filter(f => f.endsWith('.jsonl'))
    .map(f => {
      const fullPath = join(projectDir, f)
      const stat = statSync(fullPath)
      return {
        id: f.replace('.jsonl', ''),
        filename: f,
        size: stat.size,
        mtime: stat.mtimeMs,
        mtimeISO: stat.mtime.toISOString(),
        firstUserMessage: extractFirstUserMessage(fullPath)
      }
    })
    .sort((a, b) => b.mtime - a.mtime)

  return jsonResponse(files)
}

export function handleTranscriptDebugRaw(sessionId: string, url: URL): Response {
  const agent = url.searchParams.get('agent') || 'ejecutor'
  const projectDir = getProjectDir(agent)
  if (!projectDir) {
    return errorResponse(`No project directory found for agent: ${agent}`, 404)
  }

  const filePath = join(projectDir, `${sessionId}.jsonl`)
  if (!existsSync(filePath)) {
    return errorResponse(`Session ${sessionId} not found`, 404)
  }

  const content = readFileSync(filePath, 'utf-8')
  return new Response(content, {
    status: 200,
    headers: {
      'Content-Type': 'text/plain; charset=utf-8',
      ...corsHeaders
    }
  })
}

export function handleTranscriptDebugStatus(url: URL): Response {
  const sessionId = url.searchParams.get('sessionId')
  if (!sessionId) return jsonResponse({ processing: false })
  return jsonResponse({ processing: runningProcesses.has(sessionId) })
}

export async function handleTranscriptDebugSend(req: Request): Promise<Response> {
  if (req.method !== 'POST') {
    return errorResponse('Method not allowed', 405)
  }

  let body: { agent?: string; sessionId?: string; prompt?: string }
  try {
    body = await req.json()
  } catch {
    return errorResponse('Invalid JSON body')
  }

  const { agent = 'ejecutor', sessionId, prompt } = body

  if (!sessionId) return errorResponse('sessionId is required')
  if (!prompt?.trim()) return errorResponse('prompt is required')
  if (!AGENT_COMMANDS[agent]) return errorResponse(`Unknown agent: ${agent}`)

  // Verify session file exists
  const projectDir = getProjectDir(agent)
  if (!projectDir) return errorResponse(`No project directory for agent: ${agent}`, 404)

  const sessionFile = join(projectDir, `${sessionId}.jsonl`)
  if (!existsSync(sessionFile)) {
    return errorResponse(`Session ${sessionId} not found`, 404)
  }

  // Prevent concurrent sends to the same session
  if (runningProcesses.has(sessionId)) {
    return errorResponse('A prompt is already being processed for this session', 409)
  }

  // Use the agent .cmd wrapper directly (handles CLAUDE_CONFIG_DIR + cd)
  // Escape double quotes for cmd.exe and pass as single command string
  const agentCmd = AGENT_COMMANDS[agent]
  const escaped = prompt.replace(/"/g, '""')
  const cmd = `${agentCmd} --resume "${sessionId}" --permission-mode default -p "${escaped}"`

  const env = { ...process.env }
  delete env.CLAUDECODE

  console.log(`[TranscriptDebug] Spawning: ${agentCmd} --resume ${sessionId.slice(0, 8)}...`)

  const child = spawn(cmd, {
    cwd: WORKING_DIR,
    env,
    stdio: ['ignore', 'pipe', 'pipe'],
    shell: true
  } as any)

  // Track the running process
  runningProcesses.set(sessionId, {
    pid: child.pid || 0,
    kill: () => child.kill()
  })

  let stderr = ''
  child.stdout?.on('data', (data: Buffer) => {
    console.log(`[TranscriptDebug] stdout: ${data.toString().slice(0, 200)}`)
  })
  child.stderr?.on('data', (data: Buffer) => { stderr += data.toString() })

  child.on('close', (code) => {
    runningProcesses.delete(sessionId)
    if (code !== 0) {
      console.error(`[TranscriptDebug] claude exited with code ${code}`)
      if (stderr) console.error(`[TranscriptDebug] stderr: ${stderr.slice(0, 500)}`)
    } else {
      console.log(`[TranscriptDebug] claude completed for session ${sessionId.slice(0, 8)}...`)
    }
    // Notify frontend via WebSocket
    if (broadcastFn) {
      broadcastFn(JSON.stringify({
        type: 'transcript-debug-done',
        sessionId,
        exitCode: code
      }))
    }
  })

  child.on('error', (err) => {
    runningProcesses.delete(sessionId)
    console.error(`[TranscriptDebug] Failed to spawn claude:`, err.message)
    if (broadcastFn) {
      broadcastFn(JSON.stringify({
        type: 'transcript-debug-done',
        sessionId,
        error: err.message
      }))
    }
  })

  return jsonResponse({
    success: true,
    pid: child.pid,
    message: `Prompt sent to ${agent} session ${sessionId.slice(0, 8)}...`
  })
}
