import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { createFileRoute } from '@tanstack/react-router'
import YAML from 'yaml'
import { createCapabilityUnavailablePayload } from '@/lib/feature-gates'
import { isAuthenticated } from '../../server/auth-middleware'
import {
  ensureGatewayProbed,
  getCapabilities,
} from '../../server/gateway-capabilities'
import { requireJsonContentType } from '../../server/rate-limit'
import { restartHermesAgentForProfile } from '../../server/hermes-agent'

const HERMES_HOME = path.join(os.homedir(), '.hermes')
const ACTIVE_PROFILE_PATH = path.join(HERMES_HOME, 'active_profile')
const PROFILE_ID_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/
const PROFILE_DIRS = [
  'memories',
  'sessions',
  'skills',
  'skins',
  'logs',
  'plans',
  'workspace',
  'cron',
]
const CLONE_CONFIG_FILES = ['config.yaml', '.env', 'SOUL.md']

type HermesProfile = {
  name: string
  path: string
  is_default: boolean
  is_active: boolean
  gateway_running: boolean
  model: string | null
  provider: string | null
  has_env: boolean
  skill_count: number
}

function resolveProfileHome(name: string): string {
  return name === 'default'
    ? HERMES_HOME
    : path.join(HERMES_HOME, 'profiles', name)
}

function readActiveProfileName(): string {
  try {
    if (!fs.existsSync(ACTIVE_PROFILE_PATH)) return 'default'
    const raw = fs.readFileSync(ACTIVE_PROFILE_PATH, 'utf-8').trim()
    return raw || 'default'
  } catch {
    return 'default'
  }
}

function writeActiveProfileName(name: string): void {
  fs.writeFileSync(ACTIVE_PROFILE_PATH, name === 'default' ? '' : name, 'utf-8')
}

function readProfileConfig(profileHome: string): Record<string, unknown> {
  try {
    const raw = fs.readFileSync(path.join(profileHome, 'config.yaml'), 'utf-8')
    return (YAML.parse(raw) as Record<string, unknown>) || {}
  } catch {
    return {}
  }
}

function getProfileMetadata(name: string, activeName: string): HermesProfile {
  const profileHome = resolveProfileHome(name)
  const config = readProfileConfig(profileHome)
  const modelField = config.model
  let model: string | null = null
  let provider: string | null = null
  if (typeof modelField === 'string' && modelField.trim()) {
    model = modelField.trim()
  } else if (modelField && typeof modelField === 'object') {
    const modelObj = modelField as Record<string, unknown>
    model =
      typeof modelObj.default === 'string' && modelObj.default.trim()
        ? modelObj.default.trim()
        : null
    provider =
      typeof modelObj.provider === 'string' && modelObj.provider.trim()
        ? modelObj.provider.trim()
        : null
  }
  if (!provider && typeof config.provider === 'string' && config.provider.trim()) {
    provider = config.provider.trim()
  }

  const skillsDir = path.join(profileHome, 'skills')
  const skillCount = fs.existsSync(skillsDir)
    ? (fs.readdirSync(skillsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).length)
    : 0

  const pidPath = path.join(profileHome, 'gateway.pid')
  let gatewayRunning = false
  if (fs.existsSync(pidPath)) {
    try {
      const raw = fs.readFileSync(pidPath, 'utf-8').trim()
      const parsed = raw.startsWith('{')
        ? (JSON.parse(raw) as { pid?: unknown })
        : { pid: Number(raw) }
      if (typeof parsed.pid === 'number' && parsed.pid > 0) {
        process.kill(parsed.pid, 0)
        gatewayRunning = true
      }
    } catch {}
  }

  return {
    name,
    path: profileHome,
    is_default: name === 'default',
    is_active: name === activeName,
    gateway_running: gatewayRunning,
    model,
    provider,
    has_env: fs.existsSync(path.join(profileHome, '.env')),
    skill_count: skillCount,
  }
}

function listProfiles(): Array<HermesProfile> {
  const activeName = readActiveProfileName()
  const profiles: Array<HermesProfile> = [getProfileMetadata('default', activeName)]
  const profilesRoot = path.join(HERMES_HOME, 'profiles')
  if (fs.existsSync(profilesRoot)) {
    for (const entry of fs.readdirSync(profilesRoot, { withFileTypes: true })) {
      if (!entry.isDirectory()) continue
      profiles.push(getProfileMetadata(entry.name, activeName))
    }
  }
  return profiles
}

function validateProfileName(name: string): string {
  const trimmed = String(name || '').trim()
  if (trimmed === 'default') {
    throw new Error("Cannot create a profile named 'default'.")
  }
  if (!PROFILE_ID_RE.test(trimmed)) {
    throw new Error(
      `Invalid profile name ${JSON.stringify(trimmed)}. Must match [a-z0-9][a-z0-9_-]{0,63}`,
    )
  }
  return trimmed
}

function createProfile(name: string, cloneFrom: string, cloneConfig: boolean): HermesProfile {
  const profileName = validateProfileName(name)
  const profileHome = resolveProfileHome(profileName)
  if (fs.existsSync(profileHome)) {
    throw new Error(`Profile '${profileName}' already exists.`)
  }
  fs.mkdirSync(profileHome, { recursive: false })
  for (const dir of PROFILE_DIRS) {
    fs.mkdirSync(path.join(profileHome, dir), { recursive: true })
  }
  if (cloneConfig) {
    const sourceHome = resolveProfileHome(cloneFrom || readActiveProfileName())
    for (const filename of CLONE_CONFIG_FILES) {
      const source = path.join(sourceHome, filename)
      if (fs.existsSync(source)) {
        fs.copyFileSync(source, path.join(profileHome, filename))
      }
    }
  }
  return getProfileMetadata(profileName, readActiveProfileName())
}

function deleteProfile(name: string): void {
  if (name === 'default') throw new Error('Cannot delete the default profile.')
  const profileHome = resolveProfileHome(name)
  if (!fs.existsSync(profileHome)) {
    throw new Error(`Profile '${name}' does not exist.`)
  }
  fs.rmSync(profileHome, { recursive: true, force: true })
}

export const Route = createFileRoute('/api/hermes-profiles')({
  server: {
    handlers: {
      GET: async ({ request }) => {
        if (!isAuthenticated(request)) {
          return Response.json({ ok: false, error: 'Unauthorized' }, { status: 401 })
        }
        await ensureGatewayProbed()
        if (!getCapabilities().config) {
          return Response.json({
            ...createCapabilityUnavailablePayload('config'),
            profiles: [],
            active: 'default',
          })
        }
        const profiles = listProfiles()
        return Response.json({
          ok: true,
          active: readActiveProfileName(),
          profiles,
        })
      },
      POST: async ({ request }) => {
        if (!isAuthenticated(request)) {
          return Response.json({ ok: false, error: 'Unauthorized' }, { status: 401 })
        }
        await ensureGatewayProbed()
        if (!getCapabilities().config) {
          return Response.json(
            createCapabilityUnavailablePayload('config', {
              error: 'Profile management is unavailable on this backend.',
            }),
            { status: 503 },
          )
        }
        const csrfCheck = requireJsonContentType(request)
        if (csrfCheck) return csrfCheck
        try {
          const body = (await request.json()) as Record<string, unknown>
          const action = String(body.action || '').trim()

          if (action === 'switch') {
            const nextName = String(body.name || '').trim() || 'default'
            const previousName = readActiveProfileName()
            const nextHome = resolveProfileHome(nextName)
            if (!fs.existsSync(nextHome)) {
              throw new Error(`Profile '${nextName}' does not exist.`)
            }
            writeActiveProfileName(nextName)
            const restartResult = await restartHermesAgentForProfile(
              nextHome,
              resolveProfileHome(previousName),
            )
            return Response.json({
              ok: restartResult.ok,
              active: nextName,
              profiles: listProfiles(),
              restart: restartResult,
            })
          }

          if (action === 'create') {
            const currentActive = readActiveProfileName()
            const created = createProfile(
              String(body.name || ''),
              String(body.clone_from || currentActive || 'default'),
              body.clone_config !== false,
            )
            return Response.json({
              ok: true,
              profile: created,
              active: currentActive,
              profiles: listProfiles(),
            })
          }

          if (action === 'delete') {
            const name = String(body.name || '').trim()
            if (!name) throw new Error('Missing profile name.')
            deleteProfile(name)
            return Response.json({
              ok: true,
              active: readActiveProfileName(),
              profiles: listProfiles(),
            })
          }

          return Response.json({ ok: false, error: 'Unsupported action.' }, { status: 400 })
        } catch (error) {
          return Response.json(
            { ok: false, error: error instanceof Error ? error.message : String(error) },
            { status: 400 },
          )
        }
      },
    },
  },
})
