#!/usr/bin/env node

/**
 * Claude Code Plugin CLI
 *
 * Command-line interface for managing Claude Code plugins
 * Inspired by Conduit's CLI interface
 */

import { PluginManager } from './plugin-manager'
import { HookSystem } from './hook-system'
import { SecurityManager } from './security'
import { resolve } from 'path'

// ============================================================================
// CLI CLASS
// ============================================================================

class PluginCLI {
  private pluginManager: PluginManager
  private hookSystem: HookSystem
  private security: SecurityManager

  constructor() {
    const claudeDir = process.env.CLAUDE_DIR || resolve(process.env.HOME || '', '.claude')
    this.pluginManager = new PluginManager(claudeDir)
    this.hookSystem = new HookSystem(claudeDir)
    this.security = new SecurityManager()
  }

  async run(args: string[]): Promise<void> {
    const [command, ...rest] = args

    try {
      await this.initialize()

      switch (command) {
        case 'discover':
        case 'list':
          await this.discover(rest[0])
          break

        case 'install':
          await this.install(rest[0], rest[1])
          break

        case 'install-github':
          await this.installFromGitHub(rest[0])
          break

        case 'uninstall':
          await this.uninstall(rest[0], rest[1])
          break

        case 'enable':
          await this.enable(rest[0], rest[1])
          break

        case 'disable':
          await this.disable(rest[0], rest[1])
          break

        case 'update':
          await this.update(rest[0], rest[1])
          break

        case 'info':
          await this.info(rest[0])
          break

        case 'hooks':
          await this.listHooks(rest[0])
          break

        case 'add-marketplace':
          await this.addMarketplace(rest[0], rest[1])
          break

        case 'validate':
          await this.validate(rest[0])
          break

        default:
          this.showHelp()
      }
    } catch (error) {
      console.error(`❌ Error: ${error instanceof Error ? error.message : String(error)}`)
      process.exit(1)
    }
  }

  private async initialize(): Promise<void> {
    await this.pluginManager.initialize()
    await this.hookSystem.initialize()
  }

  // ============================================================================
  // COMMANDS
  // ============================================================================

  private async discover(query?: string): Promise<void> {
    console.log('🔍 Discovering plugins...\n')

    const plugins = await this.pluginManager.discoverPlugins(query)

    if (plugins.length === 0) {
      console.log('No plugins found.')
      return
    }

    console.log(`Found ${plugins.length} plugin(s):\n`)

    for (const plugin of plugins) {
      console.log(`📦 ${plugin.name}`)
      console.log(`   Description: ${plugin.description}`)
      console.log(`   Version: ${plugin.version}`)
      console.log(`   Author: ${plugin.author}`)
      console.log(`   Source: ${plugin.source}`)
      console.log('')
    }
  }

  private async install(marketplace: string, pluginName?: string): Promise<void> {
    if (!marketplace) {
      throw new Error('Usage: claude-plugin install <marketplace> [plugin-name]')
    }

    if (!pluginName) {
      // Discover plugins in marketplace
      const plugins = await this.pluginManager.discoverPlugins()

      const marketplacePlugins = plugins.filter(p => p.source === marketplace)

      if (marketplacePlugins.length === 0) {
        console.log(`No plugins found in marketplace "${marketplace}"`)
        return
      }

      console.log(`\n📦 Available plugins in "${marketplace}":\n`)
      marketplacePlugins.forEach(p => {
        console.log(`  • ${p.name} - ${p.description}`)
      })

      return
    }

    console.log(`📦 Installing ${pluginName} from ${marketplace}...`)

    const plugin = await this.pluginManager.installPlugin(marketplace, pluginName)

    console.log(`\n✓ Successfully installed ${plugin.metadata.name} v${plugin.version}`)
    console.log(`  Location: ${plugin.installPath}`)
    console.log(`  Permissions: ${plugin.metadata.claude.permissions.join(', ')}`)
  }

  private async installFromGitHub(repo: string): Promise<void> {
    if (!repo) {
      throw new Error('Usage: claude-plugin install-github <user/repo>')
    }

    console.log(`📦 Installing plugin from GitHub: ${repo}...`)

    const plugin = await this.pluginManager.installFromGitHub(repo)

    console.log(`\n✓ Successfully installed ${plugin.metadata.name} v${plugin.version}`)
    console.log(`  Location: ${plugin.installPath}`)
    console.log(`  Permissions: ${plugin.metadata.claude.permissions.join(', ')}`)
  }

  private async uninstall(pluginName: string, marketplace?: string): Promise<void> {
    if (!pluginName) {
      throw new Error('Usage: claude-plugin uninstall <plugin-name> [marketplace]')
    }

    console.log(`🗑️  Uninstalling ${pluginName}...`)

    await this.pluginManager.uninstallPlugin(pluginName, marketplace)

    console.log(`✓ Successfully uninstalled ${pluginName}`)
  }

  private async enable(pluginName: string, marketplace?: string): Promise<void> {
    if (!pluginName) {
      throw new Error('Usage: claude-plugin enable <plugin-name> [marketplace]')
    }

    await this.pluginManager.enablePlugin(pluginName, marketplace)
    console.log(`✓ Enabled ${pluginName}`)
  }

  private async disable(pluginName: string, marketplace?: string): Promise<void> {
    if (!pluginName) {
      throw new Error('Usage: claude-plugin disable <plugin-name> [marketplace]')
    }

    await this.pluginManager.disablePlugin(pluginName, marketplace)
    console.log(`✓ Disabled ${pluginName}`)
  }

  private async update(pluginName: string, marketplace?: string): Promise<void> {
    if (!pluginName) {
      throw new Error('Usage: claude-plugin update <plugin-name> [marketplace]')
    }

    console.log(`🔄 Updating ${pluginName}...`)

    await this.pluginManager.updatePlugin(pluginName, marketplace)

    console.log(`✓ Updated ${pluginName}`)
  }

  private async info(pluginName: string): Promise<void> {
    if (!pluginName) {
      throw new Error('Usage: claude-plugin info <plugin-name>')
    }

    const installed = await this.pluginManager.loadInstalledPlugins()

    for (const [key, plugins] of Object.entries(installed)) {
      if (key.includes(pluginName)) {
        const plugin = plugins[0]

        console.log(`\n📦 ${plugin.metadata.name}`)
        console.log(`Version: ${plugin.version}`)
        console.log(`Description: ${plugin.metadata.description}`)
        console.log(`Author: ${plugin.metadata.author}`)
        console.log(`License: ${plugin.metadata.license || 'Not specified'}`)
        console.log(`Repository: ${plugin.metadata.repository || 'Not specified'}`)
        console.log(`\nInstalled:`)
        console.log(`  Path: ${plugin.installPath}`)
        console.log(`  Date: ${plugin.installedAt}`)
        console.log(`  Scope: ${plugin.scope}`)
        console.log(`  Enabled: ${plugin.enabled ? 'Yes' : 'No'}`)
        console.log(`\nPermissions:`)
        plugin.metadata.claude.permissions.forEach(perm => {
          console.log(`  • ${perm}`)
        })

        if (plugin.metadata.claude.commands?.length) {
          console.log(`\nCommands (${plugin.metadata.claude.commands.length}):`)
          plugin.metadata.claude.commands.forEach(cmd => {
            console.log(`  • ${cmd.name} - ${cmd.description}`)
          })
        }

        if (plugin.metadata.claude.hooks?.length) {
          console.log(`\nHooks (${plugin.metadata.claude.hooks.length}):`)
          plugin.metadata.claude.hooks.forEach(hook => {
            console.log(`  • ${hook.event} - ${hook.handler}`)
          })
        }

        return
      }
    }

    console.log(`Plugin "${pluginName}" is not installed.`)
  }

  private async listHooks(event?: string): Promise<void> {
    if (event) {
      const hooks = await this.hookSystem.listHooksByEvent(event as any)

      console.log(`\n🪝 Registered hooks for "${event}":\n`)

      if (hooks.length === 0) {
        console.log('  No hooks registered')
      }

      hooks.forEach((hook, i) => {
        console.log(`  ${i + 1}. ${hook.type}`)
        if (hook.command) console.log(`     Command: ${hook.command}`)
        if (hook.module) console.log(`     Module: ${hook.module}`)
        if (hook.priority !== undefined) console.log(`     Priority: ${hook.priority}`)
        console.log(`     Enabled: ${hook.enabled !== false}`)
      })
    } else {
      const hooks = this.hookSystem.getRegisteredHooks()

      console.log('\n🪝 All registered hooks:\n')

      for (const [evt, hookList] of hooks.entries()) {
        console.log(`${evt}: ${hookList.length} hook(s)`)
      }
    }
  }

  private async addMarketplace(name: string, url: string): Promise<void> {
    if (!name || !url) {
      throw new Error('Usage: claude-plugin add-marketplace <name> <github-url>')
    }

    // Parse GitHub URL
    const match = url.match(/github\.com\/([^\/]+)\/([^\/]+)/)

    if (!match) {
      throw new Error('Invalid GitHub URL')
    }

    const [, owner, repo] = match

    await this.pluginManager.addMarketplace(name, {
      type: 'github',
      repo: `${owner}/${repo}`,
    })

    console.log(`✓ Added marketplace "${name}"`)
  }

  private async validate(pluginPath: string): Promise<void> {
    if (!pluginPath) {
      throw new Error('Usage: claude-plugin validate <plugin-path>')
    }

    console.log(`🔍 Validating plugin at ${pluginPath}...`)

    // Check for plugin.json
    const pluginJsonPath = resolve(pluginPath, '.claude-plugin', 'plugin.json')

    console.log(`  ✓ Checking plugin.json...`)

    // Validate structure
    console.log(`  ✓ Validating structure...`)

    // Calculate integrity
    const integrity = await this.security.calculateDirectoryIntegrity(pluginPath)
    console.log(`  ✓ Integrity: ${integrity.slice(0, 16)}...`)

    console.log('\n✓ Plugin is valid!')
  }

  // ============================================================================
  // HELP
  // ============================================================================

  private showHelp(): void {
    console.log(`
Claude Code Plugin Manager

Commands:
  discover [query]           List available plugins (optional search query)
  install <marketplace>      Install a plugin from a marketplace
     [plugin-name]
  install-github <repo>      Install a plugin directly from GitHub (user/repo)
  uninstall <plugin-name>    Uninstall a plugin
     [marketplace]
  enable <plugin-name>       Enable a plugin
     [marketplace]
  disable <plugin-name>      Disable a plugin
     [marketplace]
  update <plugin-name>       Update a plugin to the latest version
     [marketplace]
  info <plugin-name>         Show detailed information about a plugin
  hooks [event]              List registered hooks (optional: specific event)
  add-marketplace <name>     Add a new plugin marketplace
     <github-url>
  validate <path>            Validate a plugin

Examples:
  claude-plugin discover
  claude-plugin discover git
  claude-plugin install claude-plugins-official hookify
  claude-plugin install-github username/my-plugin
  claude-plugin uninstall hookify
  claude-plugin info hookify
  claude-plugin hooks PreFileEdit

For more information, visit: https://github.com/anthropics/claude-code
`)
  }
}

// ============================================================================
// MAIN
// ============================================================================

async function main() {
  const cli = new PluginCLI()
  await cli.run(process.argv.slice(2))
}

main().catch((error) => {
  console.error('Fatal error:', error)
  process.exit(1)
})
