import { existsSync, readdirSync, readFileSync } from 'node:fs'
import { homedir } from 'node:os'
import { join } from 'node:path'
import {
  getResolvedCurrentProviderProfile,
  validateProviderProfile,
} from './provider-setup.js'

const DEFAULT_PARALLEL_AGENT_COUNT = 4
const MAX_PARALLEL_AGENT_COUNT = 8

function getClavueConfigDir() {
  return process.env.CLAVUE_CONFIG_DIR || join(homedir(), '.clavue')
}

function getTeamsDir() {
  return join(getClavueConfigDir(), 'teams')
}

function buildNoTeamsText() {
  return [
    `No local agent teams were found under ${getTeamsDir()}.`,
    '',
    'This usually means no team has been created in this config directory yet.',
    'Teams are created by the native TeamCreate workflow during a Clavue team session.',
    'If you are using a GPT gateway through the Anthropic-compatible route, run `/provider validate` first to confirm that native tool calling is actually available.',
    '',
    'Next step:',
    '1. Run `/provider validate` if the active route has not been verified yet.',
    '2. Ask Clavue to create a real team, for example: `Create a team named demo-team with two teammates for this repo.`',
    '3. Run `/team check` for a concrete capability and provider-readiness report.',
    '',
    'If you expected teams from another config root, check `CLAVUE_CONFIG_DIR`.',
  ].join('\n')
}

function isAgentTeamsCliOptIn() {
  return process.argv.includes('--agent-teams')
}

function isAgentTeamsEnabled() {
  if (process.env.USER_TYPE === 'ant') {
    return true
  }

  if (
    process.env.CLAVUE_DISABLE_AGENT_TEAMS === '1' ||
    ['0', 'false', 'no', 'off'].includes(
      String(process.env.CLAVUE_AGENT_TEAMS || '').toLowerCase().trim(),
    )
  ) {
    return false
  }

  return true
}

function buildFeatureDisabledText() {
  return [
    'Agent teams are disabled for this session.',
    'Clavue enables teams by default; check for `CLAVUE_DISABLE_AGENT_TEAMS=1`, `CLAVUE_AGENT_TEAMS=0`, or a rollout gate.',
    'Run `/team check` for a concrete readiness report.',
  ].join('\n')
}

function sanitizeName(value) {
  return String(value || '')
    .replace(/[^a-zA-Z0-9]/g, '-')
    .toLowerCase()
}

function readJsonFile(path) {
  try {
    if (!existsSync(path)) return null
    const raw = readFileSync(path, 'utf8').trim()
    if (!raw) return null
    return JSON.parse(raw)
  } catch {
    return null
  }
}

function getTeamConfigPath(teamName) {
  return join(getTeamsDir(), sanitizeName(teamName), 'config.json')
}

function getTeamSummaries() {
  try {
    const teamsDir = getTeamsDir()
    if (!existsSync(teamsDir)) return []
    const entries = readdirSync(teamsDir, { withFileTypes: true })
    const summaries = []

    for (const entry of entries) {
      if (!entry.isDirectory()) continue
      const config = readJsonFile(join(teamsDir, entry.name, 'config.json'))
      if (!config || !Array.isArray(config.members)) continue

      const teammates = config.members.filter(
        member => member && member.name !== 'team-lead',
      )
      const runningCount = teammates.filter(
        member => member.isActive !== false,
      ).length
      const idleCount = teammates.length - runningCount

      summaries.push({
        name: String(config.name || entry.name),
        memberCount: teammates.length,
        runningCount,
        idleCount,
      })
    }

    return summaries.sort((left, right) => left.name.localeCompare(right.name))
  } catch {
    return []
  }
}

function getCurrentTeamName(context) {
  try {
    return context?.getAppState?.()?.teamContext?.teamName || null
  } catch {
    return null
  }
}

function resolveTeamName(query) {
  const normalizedQuery = String(query || '').trim().toLowerCase()
  if (!normalizedQuery) return null
  const teams = getTeamSummaries()
  const exact = teams.find(team => team.name.toLowerCase() === normalizedQuery)
  if (exact) return exact.name
  return (
    teams.find(team => team.name.toLowerCase().includes(normalizedQuery))?.name ??
    null
  )
}

function getTeamDetails(teamName) {
  const config = readJsonFile(getTeamConfigPath(teamName))
  if (!config || !Array.isArray(config.members)) return null
  const teammates = config.members.filter(
    member => member && member.name !== 'team-lead',
  )

  return {
    name: String(config.name || teamName),
    configPath: getTeamConfigPath(teamName),
    teammates: teammates.map(member => ({
      name: String(member.name || 'unknown'),
      agentType: member.agentType ? String(member.agentType) : null,
      model: member.model ? String(member.model) : null,
      status: member.isActive === false ? 'idle' : 'running',
    })),
  }
}

function buildHelpText() {
  return [
    'Usage: /team [list|current|status [name]|show [name]|check|help]',
    '',
    `Show real local agent-team status from ${getTeamsDir()}.`,
    '',
    'Examples:',
    '  /team',
    '  /team list',
    '  /team check',
    '  /team current',
    '  /team status myteam',
    '  /team show myteam',
    '',
    'Agent teams are enabled by default in Clavue.',
    'To disable them before launch, set `CLAVUE_DISABLE_AGENT_TEAMS=1` or `CLAVUE_AGENT_TEAMS=0`.',
  ].join('\n')
}

function isAgentTeamsExplicitlyDisabled() {
  return (
    process.env.CLAVUE_DISABLE_AGENT_TEAMS === '1' ||
    ['0', 'false', 'no', 'off'].includes(
      String(process.env.CLAVUE_AGENT_TEAMS || '').toLowerCase().trim(),
    )
  )
}

function isBackgroundAgentExecutionDisabled() {
  return ['1', 'true', 'yes', 'on'].includes(
    String(process.env.CLAUDE_CODE_DISABLE_BACKGROUND_TASKS || '')
      .toLowerCase()
      .trim(),
  )
}

function getParallelDevelopmentReadinessLines() {
  const backgroundDisabled = isBackgroundAgentExecutionDisabled()
  return [
    'Parallel development readiness:',
    `Background agents: ${backgroundDisabled ? 'disabled' : 'enabled'}`,
    `Default worker count: ${DEFAULT_PARALLEL_AGENT_COUNT}`,
    `Maximum worker count: ${MAX_PARALLEL_AGENT_COUNT}`,
    'Launch contract: real Agent tool calls must be started before claiming parallel execution.',
    'Recommended command: `/parallel --agents 4 "<goal>"`',
  ]
}

const DIRECT_REPO_TOOL_LABELS = {
  Read: 'file read',
  Edit: 'file edit',
  Write: 'file write',
  NotebookEdit: 'notebook edit',
  Bash: 'shell',
  PowerShell: 'powershell',
  Glob: 'file glob',
  Grep: 'content search',
}

const WORKFLOW_TOOL_LABELS = {
  Agent: 'agent workers',
  TeamCreate: 'agent team creation',
  SendMessage: 'teammate messaging',
  TaskCreate: 'native task creation',
  TaskList: 'native task listing',
  TaskUpdate: 'native task updates',
  ToolSearch: 'deferred tool discovery',
  Skill: 'runtime skill loading',
}

function getContextAppState(context) {
  try {
    return context?.getAppState?.() ?? {}
  } catch {
    return {}
  }
}

function getContextToolNames(context) {
  return Array.isArray(context?.options?.tools)
    ? context.options.tools
        .map(tool => String(tool?.name ?? '').trim())
        .filter(Boolean)
        .sort()
    : []
}

function labelsForToolNames(toolNames, labelsByToolName) {
  const visible = new Set(toolNames)
  return Object.entries(labelsByToolName)
    .filter(([toolName]) => visible.has(toolName))
    .map(([, label]) => label)
}

function countArray(value) {
  return Array.isArray(value) ? value.length : 0
}

function countResourceEntries(resources) {
  if (!resources || typeof resources !== 'object') return 0
  return Object.values(resources).reduce(
    (total, entries) => total + countArray(entries),
    0,
  )
}

function summarizeToolNames(toolNames, limit = 16) {
  return toolNames.length <= limit
    ? toolNames.join(', ')
    : `${toolNames.slice(0, limit).join(', ')}, ... (+${toolNames.length - limit} more)`
}

function buildRuntimeCapabilityReport(context, profile) {
  const appState = getContextAppState(context)
  const toolNames = getContextToolNames(context)
  const visibleMcpToolNames = toolNames.filter(name => name.startsWith('mcp__'))
  const visibleMcpServers = Array.from(
    new Set(
      visibleMcpToolNames
        .map(name => name.split('__')[1])
        .filter(Boolean),
    ),
  ).sort()
  const mcpClients = Array.isArray(appState.mcp?.clients)
    ? appState.mcp.clients
    : []
  const disabledMcpClients = mcpClients.filter(
    client => client?.type === 'disabled',
  ).length
  const plugins = appState.plugins ?? {}
  const installationStatus = plugins.installationStatus ?? {}
  const installFailures =
    (Array.isArray(installationStatus.marketplaces)
      ? installationStatus.marketplaces.filter(item => item?.status === 'failed')
          .length
      : 0) +
    (Array.isArray(installationStatus.plugins)
      ? installationStatus.plugins.filter(item => item?.status === 'failed')
          .length
      : 0)
  const directRepoTools = labelsForToolNames(toolNames, DIRECT_REPO_TOOL_LABELS)
  const workflowTools = labelsForToolNames(toolNames, WORKFLOW_TOOL_LABELS)
  const mcpServers =
    visibleMcpServers.length > 0 ? ` across ${visibleMcpServers.join(', ')}` : ''
  const pluginState = plugins.needsRefresh
    ? 'stale until /reload-plugins'
    : 'current'

  return [
    'Runtime capability report:',
    '- Source of truth: visible tool schemas plus current app state. Plugins and skills can add guidance or components, but they cannot bypass missing tools, permissions, provider routing, or worktree readiness.',
    context?.options?.mainLoopModel
      ? `- Model route: ${context.options.mainLoopModel}.`
      : null,
    profile?.baseUrl ? `- Provider route: ${profile.baseUrl}.` : null,
    `- Direct repo tools: ${directRepoTools.length > 0 ? directRepoTools.join(', ') : 'none visible'}.`,
    `- Native workflow tools: ${workflowTools.length > 0 ? workflowTools.join(', ') : 'none visible'}.`,
    `- MCP: ${visibleMcpToolNames.length} visible tool(s)${mcpServers}; ${Math.max(mcpClients.length - disabledMcpClients, 0)} enabled server(s), ${disabledMcpClients} disabled server(s), ${countArray(appState.mcp?.commands)} prompt command(s), ${countResourceEntries(appState.mcp?.resources)} resource(s).`,
    `- Plugins: ${countArray(plugins.enabled)} enabled, ${countArray(plugins.disabled)} disabled, ${countArray(plugins.commands)} command(s), ${countArray(plugins.errors)} error(s), ${installFailures} install failure(s), active components ${pluginState}.`,
    `- Permission mode: ${appState.toolPermissionContext?.mode ?? 'unknown'}.`,
    `- Background agents: ${isBackgroundAgentExecutionDisabled() ? 'disabled' : 'enabled'}.`,
    '- Agent worktree isolation: preflight required before launch.',
    toolNames.length > 0
      ? `- Visible tool schemas: ${summarizeToolNames(toolNames)}.`
      : '- Visible tool schemas: none.',
  ]
    .filter(Boolean)
    .join('\n')
}

async function buildCapabilityText(context) {
  const isInternalBuild = process.env.USER_TYPE === 'ant'
  const cliOptIn = isAgentTeamsCliOptIn()
  const envOptIn = process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === '1'
  const enabled = isAgentTeamsEnabled()
  const profile = getResolvedCurrentProviderProfile()
  const sections = [
    'Agent teams capability:',
    `Session status: ${enabled ? 'enabled' : 'disabled'}`,
    `Build: ${isInternalBuild ? 'internal' : 'external'}`,
  ]

  if (!isInternalBuild) {
    sections.push(
      'Default: enabled by Clavue',
      `Compatibility flag (--agent-teams): ${cliOptIn ? 'present' : 'not needed'}`,
      `Legacy env opt-in (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1): ${envOptIn ? 'present' : 'not needed'}`,
      `Explicit disable: ${isAgentTeamsExplicitlyDisabled() ? 'enabled' : 'not set'}`,
      'External rollout gate: not evaluated by this standalone helper',
    )
  }

  if (!profile) {
    sections.push('', 'Active provider: not configured')
  } else {
    sections.push('', `Active provider: ${profile.name}`, `API URL: ${profile.baseUrl}`)
    try {
      const validation = await validateProviderProfile(profile)
      sections.push(`Native tool calling: ${String(validation.status || 'unknown').toUpperCase()}`)
      if (Array.isArray(validation.lines) && validation.lines.length > 0) {
        sections.push(...validation.lines.map(line => `  ${line}`))
      }
    } catch (error) {
      sections.push(
        `Native tool calling: CHECK FAILED (${error instanceof Error ? error.message : String(error)})`,
      )
    }
  }

  const nextSteps = []
  if (!enabled && !isInternalBuild && isAgentTeamsExplicitlyDisabled()) {
    nextSteps.push(
      'Unset `CLAVUE_DISABLE_AGENT_TEAMS` or set `CLAVUE_AGENT_TEAMS=1`, then restart Clavue.',
    )
  }
  if (!profile) {
    nextSteps.push(
      'Configure a provider profile with `/provider` or `clavue provider` before trying multi-agent workflows.',
    )
  } else {
    nextSteps.push(
      'Run `/provider validate` to confirm the active route supports native tool calling for team workflows.',
    )
  }
  if (enabled) {
    nextSteps.unshift(
      'Use `/parallel --agents 4 "<goal>"` or ask Clavue to create a real team for this repo once provider validation looks healthy.',
    )
  }

  return [
    ...sections,
    '',
    buildRuntimeCapabilityReport(context, profile),
    '',
    ...getParallelDevelopmentReadinessLines(),
    '',
    'Next steps:',
    ...nextSteps.map((step, index) => `${index + 1}. ${step}`),
  ].join('\n')
}

function formatTeamLine(team) {
  return `${team.name} · ${team.memberCount} teammates · ${team.runningCount} running · ${team.idleCount} idle`
}

function formatTeamStatus(teamName) {
  const details = getTeamDetails(teamName)
  if (!details) {
    return `No team named '${teamName}' was found under ${getTeamsDir()}.`
  }

  const sections = [
    `Team: ${details.name}`,
    `Config: ${details.configPath}`,
    `Teammates: ${details.teammates.length}`,
    `Running: ${details.teammates.filter(member => member.status === 'running').length}`,
    `Idle: ${details.teammates.filter(member => member.status === 'idle').length}`,
  ]

  if (details.teammates.length === 0) {
    sections.push('Members:\n- No teammates are currently registered.')
    return sections.join('\n')
  }

  sections.push(
    [
      'Members:',
      ...details.teammates.map(member => {
        const extras = [member.status, member.agentType, member.model].filter(
          Boolean,
        )
        return `- ${member.name} · ${extras.join(' · ')}`
      }),
    ].join('\n'),
  )

  return sections.join('\n')
}

export async function call(args, context) {
  const trimmedArgs = String(args || '').trim()

  if (
    trimmedArgs === 'help' ||
    trimmedArgs === '--help' ||
    trimmedArgs === '-h'
  ) {
    return {
      type: 'text',
      value: buildHelpText(),
    }
  }

  if (trimmedArgs === 'check') {
    return {
      type: 'text',
      value: await buildCapabilityText(context),
    }
  }

  if (!isAgentTeamsEnabled()) {
    return {
      type: 'text',
      value: buildFeatureDisabledText(),
    }
  }

  if (!trimmedArgs) {
    const currentTeamName = getCurrentTeamName(context)
    if (currentTeamName) {
      return {
        type: 'text',
        value: formatTeamStatus(currentTeamName),
      }
    }

    const teams = getTeamSummaries()
    if (teams.length > 0) {
      return {
        type: 'text',
        value: ['Available teams:', ...teams.map(team => `- ${formatTeamLine(team)}`), '', buildHelpText()].join('\n'),
      }
    }

    return {
      type: 'text',
      value: buildNoTeamsText(),
    }
  }

  if (trimmedArgs === 'list') {
    const teams = getTeamSummaries()
    return {
      type: 'text',
      value:
        teams.length === 0
          ? buildNoTeamsText()
          : ['Available teams:', ...teams.map(team => `- ${formatTeamLine(team)}`)].join('\n'),
    }
  }

  const statusMatch = trimmedArgs.match(/^(current|status|show)(?:\s+(.+))?$/i)
  if (statusMatch) {
    const explicitTeamName = statusMatch[2]?.trim()
    const teamName =
      explicitTeamName || getCurrentTeamName(context) || getTeamSummaries()[0]?.name
    return {
      type: 'text',
      value: teamName
        ? formatTeamStatus(teamName)
        : buildNoTeamsText(),
    }
  }

  const resolvedTeamName = resolveTeamName(trimmedArgs)
  if (resolvedTeamName) {
    return {
      type: 'text',
      value: formatTeamStatus(resolvedTeamName),
    }
  }

  return {
    type: 'text',
    value: `Unknown /team argument '${trimmedArgs}'. Run /team help for usage.`,
  }
}
