#!/usr/bin/env ruby
# SPDX-License-Identifier: GPL-3.0-only
# SPDX-FileCopyrightText: 2026 OpenVox MCP Server Contributors
# frozen_string_literal: true

require_relative '../lib/openvox_mcp'

# HTTP entry point — primary transport for external AI tools
# Usage: bin/openvox-mcp-server [options]

config_path = ENV['OPENVOX_MCP_CONFIG']
plugins = []
stateless = false
allow_remote = false
tls_cert = nil
tls_key = nil
generate_key_name = nil
list_keys = false
revoke_key_name = nil
rotate_key_name = nil
keyfile_path = nil
keyfile_explicit = false

# Parse command line arguments
i = 0
while i < ARGV.length
  case ARGV[i]
  when '--port', '-p'
    ENV['OPENVOX_MCP_PORT'] = ARGV[i + 1]
    i += 2
  when '--host', '-H'
    ENV['OPENVOX_MCP_HOST'] = ARGV[i + 1]
    i += 2
  when '--config', '-c'
    config_path = ARGV[i + 1]
    i += 2
  when '--plugin'
    plugins << ARGV[i + 1]
    i += 2
  when '--stateless'
    stateless = true
    i += 1
  when '--allow-remote'
    allow_remote = true
    i += 1
  when '--tls-cert'
    tls_cert = ARGV[i + 1]
    i += 2
  when '--tls-key'
    tls_key = ARGV[i + 1]
    i += 2
  when '--keyfile'
    keyfile_path = ARGV[i + 1]
    keyfile_explicit = true
    i += 2
  when '--generate-key'
    generate_key_name = 'default'
    i += 1
  when '--name'
    generate_key_name = ARGV[i + 1] if generate_key_name
    revoke_key_name = ARGV[i + 1] if revoke_key_name == :pending
    rotate_key_name = ARGV[i + 1] if rotate_key_name == :pending
    i += 2
  when '--list-keys'
    list_keys = true
    i += 1
  when '--revoke-key'
    revoke_key_name = :pending
    i += 1
  when '--rotate-key'
    rotate_key_name = :pending
    i += 1
  when '--help', '-h'
    puts <<~HELP
      OpenVox MCP Server — HTTP transport (Streamable HTTP)

      Usage: openvox-mcp-server [options]

      Options:
        -p, --port PORT      HTTP port (default: 9393, env: OPENVOX_MCP_PORT)
        -H, --host HOST      HTTP host (default: localhost, env: OPENVOX_MCP_HOST)
        -c, --config PATH    Path to config file (env: OPENVOX_MCP_CONFIG)
            --plugin NAME    Load a specific plugin (can be repeated)
            --stateless      Run in stateless mode (no sessions, no SSE)
            --allow-remote   Allow binding to non-localhost addresses
            --tls-cert PATH  Path to TLS certificate file (PEM)
            --tls-key PATH   Path to TLS private key file (PEM)
        -h, --help           Show this help message

      Key Management:
            --keyfile PATH         Path to keyfile (default: from config)
            --generate-key         Generate a new API key
              --name NAME          Client name for the key (default: 'default')
            --list-keys            List all keys (metadata only)
            --revoke-key --name N  Revoke a key by client name
            --rotate-key --name N  Rotate a key (revoke old, generate new)

      Security:
        By default, the server only binds to localhost. Use --allow-remote to
        bind to other addresses (e.g., 0.0.0.0). Authentication is required
        unless explicitly disabled with http.authentication.type: none in config.

      Endpoints:
        POST /   JSON-RPC requests
        GET  /   SSE stream (requires Mcp-Session-Id header)
        DELETE / End session

      Examples:
        # Start with single API key (env var mode)
        OPENVOX_MCP_API_KEY=your_key bin/openvox-mcp-server --port 9393

        # Generate a key and append hash to keyfile
        bin/openvox-mcp-server --generate-key --name claude-code

        # List all keys
        bin/openvox-mcp-server --list-keys

        # Revoke a key
        bin/openvox-mcp-server --revoke-key --name old-client

        # Start with TLS
        bin/openvox-mcp-server --tls-cert cert.pem --tls-key key.pem

    HELP
    exit 0
  else
    i += 1
  end
end

# Load configuration (env var > --config flag > auto-discovery)
# This must happen before key management commands so they use the correct keyfile_path.
config = OpenvoxMCP.configuration
config.load_from_file(config_path)

# Resolve keyfile path: explicit --keyfile > config > default
unless keyfile_explicit
  keyfile_path = config.http_security.authentication.keyfile_path
end

# Helper: notify running server to reload keys
def notify_server_reload
  if OpenvoxMCP::Server.signal_reload
    warn 'Running server notified to reload keys (SIGHUP).'
  else
    warn 'No running server detected. Keys will be loaded on next start.'
  end
end

# Handle --generate-key
if generate_key_name
  result = OpenvoxMCP::Tools::GenerateApiKey.call(
    key_name: generate_key_name,
    keyfile_path: keyfile_path
  )
  data = JSON.parse(result.content.first[:text])
  puts data['key']
  warn "Key generated for '#{generate_key_name}'. Hash appended to #{keyfile_path}."
  warn 'Store the plaintext key securely — it cannot be recovered.'
  notify_server_reload
  exit 0
end

# Handle --list-keys
if list_keys
  unless File.exist?(keyfile_path)
    warn "No keyfile found at #{keyfile_path}"
    exit 1
  end
  keyfile = OpenvoxMCP::Keyfile.new(keyfile_path)
  begin
    keyfile.load!
  rescue OpenvoxMCP::ConfigurationError => e
    warn "Error: #{e.message}"
    exit 1
  end

  puts format('%-20s %-12s %-12s %-8s', 'NAME', 'CREATED', 'EXPIRES', 'STATUS')
  puts '-' * 56
  keyfile.keys.each do |key|
    expires = key[:expires_at] ? key[:expires_at].strftime('%Y-%m-%d') : 'never'
    status = key[:enabled] ? 'active' : 'revoked'
    puts format('%-20s %-12s %-12s %-8s', key[:name], key[:created_at], expires, status)
  end
  exit 0
end

# Handle --revoke-key
if revoke_key_name && revoke_key_name != :pending
  keyfile = OpenvoxMCP::Keyfile.new(keyfile_path)
  begin
    keyfile.load!
    keyfile.revoke_key(revoke_key_name)
    warn "Key '#{revoke_key_name}' revoked."
    notify_server_reload
  rescue OpenvoxMCP::ConfigurationError => e
    warn "Error: #{e.message}"
    exit 1
  end
  exit 0
end

# Handle --rotate-key
if rotate_key_name && rotate_key_name != :pending
  keyfile = OpenvoxMCP::Keyfile.new(keyfile_path)
  begin
    keyfile.load!
    keyfile.revoke_key(rotate_key_name)
    result = OpenvoxMCP::Tools::GenerateApiKey.call(
      key_name: rotate_key_name,
      keyfile_path: keyfile_path
    )
    data = JSON.parse(result.content.first[:text])
    puts data['key']
    warn "Key '#{rotate_key_name}' rotated. Old key revoked, new key generated."
    warn 'Store the plaintext key securely — it cannot be recovered.'
    notify_server_reload
  rescue OpenvoxMCP::ConfigurationError => e
    warn "Error: #{e.message}"
    exit 1
  end
  exit 0
end

OpenvoxMCP::Server.run_http(
  config_path: config_path,
  plugins: plugins,
  stateless: stateless,
  allow_remote: allow_remote,
  tls_cert: tls_cert,
  tls_key: tls_key
)
