/**
 * Tor Integration Service
 * Provides Tor network connectivity for anonymous plant sharing
 */

import { SocksProxyAgent } from 'socks-proxy-agent';

export interface TorConfig {
  enabled: boolean;
  socksHost: string;
  socksPort: number;
  controlPort: number;
  hiddenServiceDir?: string;
}

export class TorService {
  private config: TorConfig;
  private proxyAgent: any;

  constructor(config?: Partial<TorConfig>) {
    this.config = {
      enabled: process.env.TOR_ENABLED === 'true',
      socksHost: process.env.TOR_SOCKS_HOST || '127.0.0.1',
      socksPort: parseInt(process.env.TOR_SOCKS_PORT || '9050'),
      controlPort: parseInt(process.env.TOR_CONTROL_PORT || '9051'),
      hiddenServiceDir: process.env.TOR_HIDDEN_SERVICE_DIR,
      ...config,
    };

    if (this.config.enabled) {
      this.initializeProxy();
    }
  }

  /**
   * Initialize SOCKS proxy for Tor
   */
  private initializeProxy(): void {
    const proxyUrl = `socks5://${this.config.socksHost}:${this.config.socksPort}`;
    this.proxyAgent = new SocksProxyAgent(proxyUrl);
  }

  /**
   * Check if Tor is available and running
   */
  async isAvailable(): Promise<boolean> {
    if (!this.config.enabled) return false;

    try {
      // Try to fetch check.torproject.org through Tor
      const response = await fetch('https://check.torproject.org/api/ip', {
        // @ts-ignore
        agent: this.proxyAgent,
        signal: AbortSignal.timeout(5000),
      });

      const data = await response.json();
      return data.IsTor === true;
    } catch (error) {
      console.error('Tor availability check failed:', error);
      return false;
    }
  }

  /**
   * Fetch data through Tor network
   */
  async fetchThroughTor(url: string, options: RequestInit = {}): Promise<Response> {
    if (!this.config.enabled) {
      throw new Error('Tor is not enabled');
    }

    return fetch(url, {
      ...options,
      // @ts-ignore
      agent: this.proxyAgent,
    });
  }

  /**
   * Get current Tor circuit info
   */
  async getCircuitInfo(): Promise<{ country?: string; ip?: string }> {
    try {
      const response = await this.fetchThroughTor('https://check.torproject.org/api/ip');
      return await response.json();
    } catch (error) {
      return {};
    }
  }

  /**
   * Request new Tor identity (new circuit)
   */
  async requestNewIdentity(): Promise<boolean> {
    // This would require Tor control port access
    // For now, just return true if Tor is enabled
    return this.config.enabled;
  }

  /**
   * Get onion service hostname if available
   */
  getOnionAddress(): string | null {
    if (!this.config.hiddenServiceDir) return null;

    try {
      const fs = require('fs');
      const path = require('path');
      const hostnamePath = path.join(this.config.hiddenServiceDir, 'hostname');

      if (fs.existsSync(hostnamePath)) {
        return fs.readFileSync(hostnamePath, 'utf-8').trim();
      }
    } catch (error) {
      console.error('Error reading onion address:', error);
    }

    return null;
  }

  /**
   * Generate QR code for onion address
   */
  async generateOnionQRCode(): Promise<string | null> {
    const onionAddress = this.getOnionAddress();
    if (!onionAddress) return null;

    // In production, you'd use a QR code library
    // For now, return the address
    return `http://${onionAddress}`;
  }

  /**
   * Check if request came through Tor
   */
  isRequestFromTor(headers: any): boolean {
    // Check various indicators that request came through Tor
    return (
      headers['x-tor-connection'] === 'true' ||
      headers['x-forwarded-proto'] === 'tor' ||
      false
    );
  }
}

// Singleton instance
let torService: TorService | null = null;

export function getTorService(): TorService {
  if (!torService) {
    torService = new TorService();
  }
  return torService;
}

/**
 * Middleware to detect and mark Tor connections
 */
export function torDetectionMiddleware(req: any, res: any, next: any) {
  const torService = getTorService();

  // Mark request as coming from Tor if detected
  req.isTorConnection = torService.isRequestFromTor(req.headers);

  // Add Tor status to response headers
  if (req.isTorConnection) {
    res.setHeader('X-Tor-Enabled', 'true');
  }

  next();
}
