import { Command } from 'commander';
import {
  createNode,
  importKeyPair,
  createDHTOperations,
} from '@highway1/core';
import { getIdentity, getBootstrapPeers } from '../config.js';
import { error, spinner, printHeader, info, success } from '../ui.js';
import Table from 'cli-table3';

export function registerDiscoverCommand(program: Command): void {
  program
    .command('discover')
    .description('Discover agents on the network')
    .option('--capability <capability>', 'Filter by capability')
    .option('--did <did>', 'Query specific DID')
    .option('--query <text>', 'Natural language query (e.g., "translate Japanese")')
    .option('--min-trust <score>', 'Minimum trust score (0-1)')
    .option('--language <lang>', 'Filter by language')
    .option('--limit <number>', 'Maximum number of results', '10')
    .option('--bootstrap <peers...>', 'Bootstrap peer addresses')
    .action(async (options) => {
      try {
        printHeader('Discover Agents');

        const identity = getIdentity();

        if (!identity) {
          error('No identity found. Run "hw1 init" first.');
          process.exit(1);
        }

        const spin = spinner('Starting node...');

        const keyPair = importKeyPair({
          publicKey: identity.publicKey,
          privateKey: identity.privateKey,
        });

        const bootstrapPeers = options.bootstrap || getBootstrapPeers();

        const node = await createNode({
          keyPair,
          bootstrapPeers,
          enableDHT: true,
        });

        await node.start();

        spin.text = 'Waiting for DHT peers...';
        // Wait until connected to at least one peer, or timeout after 15s
        await new Promise<void>((resolve) => {
          const timeout = setTimeout(resolve, 15000);
          node.libp2p.addEventListener('peer:connect', () => {
            clearTimeout(timeout);
            setTimeout(resolve, 1000); // brief settle time after first connection
          }, { once: true });
        });

        spin.text = 'Querying DHT...';

        const dht = createDHTOperations(node.libp2p);

        if (options.did) {
          const card = await dht.queryAgentCard(options.did);

          if (card) {
            spin.succeed('Agent found!');
            console.log();
            info(`DID:          ${card.did}`);
            info(`Name:         ${card.name}`);
            info(`Description:  ${card.description}`);
            info(`Version:      ${card.version}`);
            info(`Capabilities: ${card.capabilities.join(', ') || '(none)'}`);
            info(`Peer ID:      ${card.peerId || '(unknown)'}`);
            info(`Endpoints:    ${card.endpoints.length > 0 ? card.endpoints.join('\n              ') : '(none)'}`);
            info(`Timestamp:    ${new Date(card.timestamp).toISOString()}`);
          } else {
            spin.fail('Agent not found');
          }
        } else if (options.capability || options.query) {
          // Semantic search
          const query: any = {
            limit: parseInt(options.limit, 10),
          };

          if (options.query) {
            query.text = options.query;
          } else if (options.capability) {
            query.capability = options.capability;
          }

          if (options.minTrust) {
            query.filters = {
              minTrustScore: parseFloat(options.minTrust),
            };
          }

          if (options.language) {
            query.filters = query.filters || {};
            query.filters.language = options.language;
          }

          const cards = await dht.searchSemantic(query);

          spin.succeed(`Found ${cards.length} agents`);

          if (cards.length > 0) {
            const table = new Table({
              head: ['DID', 'Name', 'Capabilities', 'Trust'],
              colWidths: [40, 20, 35, 10],
            });

            for (const card of cards) {
              const capabilities = Array.isArray(card.capabilities)
                ? card.capabilities.map((cap: any) =>
                    typeof cap === 'string' ? cap : cap.name
                  ).join(', ')
                : '';

              const trustScore = card.trust
                ? `${(card.trust.interactionScore * 100).toFixed(0)}%`
                : 'N/A';

              table.push([
                card.did.substring(0, 35) + '...',
                card.name,
                capabilities.substring(0, 30) + (capabilities.length > 30 ? '...' : ''),
                trustScore,
              ]);
            }

            console.log();
            console.log(table.toString());

            // Show detailed info for first result if query was used
            if (options.query && cards.length > 0) {
              const card = cards[0];
              console.log();
              info('Top match details:');
              info(`  DID:         ${card.did}`);
              info(`  Name:        ${card.name}`);
              info(`  Description: ${card.description}`);

              if (Array.isArray(card.capabilities) && card.capabilities.length > 0) {
                const cap = card.capabilities[0];
                if (typeof cap === 'object' && cap !== null) {
                  info(`  Capability:  ${cap.name}`);
                  info(`               ${cap.description}`);
                }
              }
            }
          }
        } else {
          spin.fail('Please specify --did, --capability, or --query');
          info('Usage: hw1 discover --did <did>');
          info('       hw1 discover --capability <capability>');
          info('       hw1 discover --query "translate Japanese"');
          info('       hw1 discover --query "code review" --min-trust 0.8');
        }

        await node.stop();
      } catch (err) {
        error(`Failed to discover: ${(err as Error).message}`);
        process.exit(1);
      }
    });
}
