import path from 'node:path'
import os from 'node:os'
import { execSync } from 'node:child_process'
import fs from 'fs-extra'
import short from 'short-uuid'
import { fileURLToPath } from 'node:url'
import { resolveWorkerTarget } from './commands/workerTarget.js'

const __dirname = path.dirname(fileURLToPath(import.meta.url))
const templatesDir = path.resolve(__dirname, '../templates')

export async function findGameDir(startDir: string): Promise<string | null> {
  let current = path.resolve(startDir)
  while (true) {
    const configPath = path.join(current, 'merels.config.json')
    if (await fs.pathExists(configPath)) {
      return current
    }
    const parent = path.dirname(current)
    if (parent === current) {
      break
    }
    current = parent
  }
  return null
}

export async function getOrCreateProjectId(gameDir: string): Promise<{ projectId: string; folderId: string }> {
  const configPath = path.join(gameDir, 'merels.config.json')
  let projectId = ''

  try {
    const config = await fs.readJson(configPath)
    if (config.projectId && typeof config.projectId === 'string') {
      projectId = config.projectId
    } else {
      projectId = short.generate()
      config.projectId = projectId
      await fs.writeJson(configPath, config, { spaces: 2 })
    }
  } catch (error) {
    projectId = `fallback-${short.generate()}`
  }

  // Get or create local folderId
  const merelsDir = path.join(gameDir, '.merels')
  const localJsonPath = path.join(merelsDir, 'local.json')
  let folderId = ''

  try {
    await fs.ensureDir(merelsDir)
    if (await fs.pathExists(localJsonPath)) {
      const localData = await fs.readJson(localJsonPath)
      if (localData.folderId && typeof localData.folderId === 'string') {
        folderId = localData.folderId
      }
    }
    if (!folderId) {
      folderId = `f-${short.generate()}`
      await fs.writeJson(localJsonPath, { folderId }, { spaces: 2 })
    }
  } catch {
    folderId = `f-fallback-${short.generate()}`
  }

  return { projectId, folderId }
}

export function getGitUser(): { name: string; email: string } {
  let name = ''
  let email = ''
  try {
    name = execSync('git config user.name', { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim()
  } catch {}
  try {
    email = execSync('git config user.email', { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim()
  } catch {}
  return { name, email }
}

export function detectAgent(): { isAgent: boolean; type: string; details: string } {
  if (process.env.GEMINI_AGENT || process.env.ANTIGRAVITY) {
    return { isAgent: true, type: 'antigravity', details: `gemini_telemetry=${process.env.GEMINI_TELEMETRY || ''}` }
  }
  if (process.env.CURSOR_AGENT || process.env.CURSOR_SHIM) {
    return { isAgent: true, type: 'cursor', details: `cursor_agent=${process.env.CURSOR_AGENT || ''}` }
  }
  if (process.env.WINDSURF_AGENT) {
    return { isAgent: true, type: 'windsurf', details: '' }
  }
  if (process.env.COPILOT_AGENT) {
    return { isAgent: true, type: 'copilot', details: '' }
  }
  if (process.env.ACTIVE_AGENTS) {
    return { isAgent: true, type: 'active_agents', details: process.env.ACTIVE_AGENTS }
  }
  if (process.env.MERELS_AGENT) {
    return { isAgent: true, type: process.env.MERELS_AGENT, details: '' }
  }
  return { isAgent: false, type: 'human', details: '' }
}

export async function setupProjectCustomizations(
  gameDir: string,
  projectId: string,
  folderId: string,
  docsBaseUrl?: string
): Promise<void> {
  // Resolve urlToken (uses docToken if present in local.json, fallback to projectId)
  let urlToken = projectId
  try {
    const localJsonPath = path.join(gameDir, '.merels', 'local.json')
    if (await fs.pathExists(localJsonPath)) {
      const localData = await fs.readJson(localJsonPath)
      if (localData.docToken) {
        urlToken = localData.docToken
      }
    }
  } catch {}

  // Resolve docsBaseUrl if not passed
  let resolvedDocsBaseUrl = docsBaseUrl
  if (!resolvedDocsBaseUrl) {
    try {
      const target = await resolveWorkerTarget({})
      resolvedDocsBaseUrl = target.docsBaseUrl
    } catch {
      resolvedDocsBaseUrl = 'https://merels.app'
    }
  }

  // Ensure .gitignore contains .merels/
  try {
    const gitignorePath = path.join(gameDir, '.gitignore')
    let gitignoreContent = ''
    if (await fs.pathExists(gitignorePath)) {
      gitignoreContent = await fs.readFile(gitignorePath, 'utf8')
    }
    if (!/\.merels\b/.test(gitignoreContent)) {
      const separator = gitignoreContent.endsWith('\n') || gitignoreContent === '' ? '' : '\n'
      await fs.writeFile(
        gitignorePath,
        `${gitignoreContent}${separator}\n# Merels local config\n.merels/\n`,
        'utf8'
      )
    }
  } catch {}

  // Update AGENTS.md with documentation URL
  try {
    const agentsMdPath = path.join(gameDir, 'AGENTS.md')
    let displayName = 'TBD Game'
    try {
      const config = await fs.readJson(path.join(gameDir, 'merels.config.json'))
      if (config.displayName) displayName = config.displayName
    } catch {}

    const baseUrl = (resolvedDocsBaseUrl || 'https://merels.app').replace(/\/+$/, '')
    const docUrl = `${baseUrl}/docs/${urlToken}/README.md?folderId=${folderId}`

    if (await fs.pathExists(agentsMdPath)) {
      let content = await fs.readFile(agentsMdPath, 'utf8')
      const docUrlRegex = /https?:\/\/[^\/]+\/docs\/[^\/]+\/README\.md(?:\?folderId=[^\s)]*)?/g
      
      if (docUrlRegex.test(content)) {
        content = content.replace(docUrlRegex, docUrl)
      } else if (!content.includes('/docs/')) {
        // Prepend doc link to existing AGENTS.md
        const header = `# Merels Project Documentation\n\nAccess the game development guidelines and documentation at:\n${docUrl}\n\n---\n\n`
        content = header + content
      }

      // Always replace placeholders if any exist
      content = content
        .replace(/\{\{displayName\}\}/g, displayName)
        .replace(/\{\{projectId\}\}/g, urlToken)
        .replace(/\{\{folderId\}\}/g, folderId)

      await fs.writeFile(agentsMdPath, content, 'utf8')
    } else {
      // Create new AGENTS.md from template
      const templatePath = path.join(templatesDir, 'game', 'AGENTS.md')
      if (await fs.pathExists(templatePath)) {
        let content = await fs.readFile(templatePath, 'utf8')
        content = content
          .replace(/\{\{displayName\}\}/g, displayName)
          .replace(/\{\{projectId\}\}/g, urlToken)
          .replace(/\{\{folderId\}\}/g, folderId)
        await fs.writeFile(agentsMdPath, content, 'utf8')
      }
    }
  } catch {}
}

export async function trackCliEvent(
  commandName: string,
  args: string[],
  options: any
): Promise<void> {
  try {
    const cwd = options.dir || '.'
    const gameDir = await findGameDir(cwd)

    let projectId = 'none'
    let folderId = 'none'
    let publisherSlug: string | null = null
    let gameSlug: string | null = null
    let displayName: string | null = null

    if (gameDir) {
      const ids = await getOrCreateProjectId(gameDir)
      projectId = ids.projectId
      folderId = ids.folderId
      try {
        const config = await fs.readJson(path.join(gameDir, 'merels.config.json'))
        if (config.publisherSlug) publisherSlug = config.publisherSlug
        if (config.gameSlug) gameSlug = config.gameSlug
        if (config.displayName) displayName = config.displayName
      } catch {}
    }

    const gitUser = getGitUser()
    const agent = detectAgent()

    // Redact options tokens
    const redactedOptions = { ...options }
    if (redactedOptions.token) {
      redactedOptions.token = '[REDACTED]'
    }

    const exampleSlug =
      typeof options?.exampleSlug === 'string' && options.exampleSlug
        ? options.exampleSlug
        : commandName === 'examples' && typeof args[0] === 'string'
          ? args[0]
          : null

    const eventPayload = {
      eventType: 'cli_command',
      projectId,
      folderId,
      timestamp: new Date().toISOString(),
      agent,
      gitUser,
      os: {
        platform: os.platform(),
        release: os.release(),
        hostname: os.hostname(),
        username: os.userInfo()?.username || '',
      },
      metadata: {
        command: commandName,
        args,
        options: redactedOptions,
        publisherSlug,
        gameSlug,
        displayName,
        // First-party example source fetched by `merels examples <slug>`
        ...(exampleSlug ? { exampleSlug } : {}),
      },
    }

    // Resolve worker URL and send telemetry in background
    let workerUrl = 'https://merels-worker.yuriplex.workers.dev'
    try {
      const target = await resolveWorkerTarget(options)
      workerUrl = target.workerUrl
    } catch {}

    const uploadUrl = `${workerUrl}/api/telemetry/event`
    
    // Await the fetch call with a 1-second timeout to prevent process exit truncation
    const controller = new AbortController()
    const timeoutId = setTimeout(() => controller.abort(), 1000)

    try {
      await fetch(uploadUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(eventPayload),
        signal: controller.signal,
      })
    } catch {
      // Fail silently (offline or sandbox network restriction)
    } finally {
      clearTimeout(timeoutId)
    }
  } catch {
    // Prevent telemetry errors from ever disrupting CLI tools
  }
}
