/**
 * Unified proxy agent — supports HTTP/HTTPS/SOCKS5/SOCKS5h protocols.
 *
 * Node 20+ native fetch() uses undici Dispatcher, but socks-proxy-agent
 * doesn't implement this interface.
 * Solution: use http.Agent interface + http/https.request().
 */

let HttpsProxyAgent: any;
let SocksProxyAgent: any;

try {
  HttpsProxyAgent = require('https-proxy-agent').HttpsProxyAgent;
} catch {
  try {
    HttpsProxyAgent = require('https-proxy-agent');
  } catch {}
}

try {
  SocksProxyAgent = require('socks-proxy-agent').SocksProxyAgent;
} catch {
  try {
    SocksProxyAgent = require('socks-proxy-agent');
  } catch {}
}

/** Create an http.Agent for the given proxy URL (works with https.request) */
function createProxyAgent(proxyUrl?: string): any {
  if (!proxyUrl || typeof proxyUrl !== 'string') return null;
  const trimmed = proxyUrl.trim();
  if (!trimmed) return null;
  const lower = trimmed.toLowerCase();
  try {
    if (lower.startsWith('socks5://') || lower.startsWith('socks5h://')) {
      if (!SocksProxyAgent) {
        console.warn('[Proxy] socks-proxy-agent not installed');
        return null;
      }
      return new SocksProxyAgent(trimmed);
    }
    if (lower.startsWith('http://') || lower.startsWith('https://')) {
      if (!HttpsProxyAgent) {
        console.warn('[Proxy] No HTTP proxy agent available');
        return null;
      }
      return new HttpsProxyAgent(trimmed);
    }
    // Unknown scheme — try as HTTP proxy
    if (HttpsProxyAgent) return new HttpsProxyAgent(trimmed);
    return null;
  } catch (err: any) {
    console.error(`[Proxy] Failed to create proxy agent: ${err.message}`);
    return null;
  }
}

/**
 * Fetch with proxy support.
 * Uses native fetch() when no proxy, or http/https.request() with agent when proxy is set.
 */
export async function proxiedFetch(
  url: string,
  init?: RequestInit,
  proxyUrl?: string
): Promise<Response> {
  if (!proxyUrl) return fetch(url, init);

  const agent = createProxyAgent(proxyUrl);
  if (!agent) return fetch(url, init);

  const parsedUrl = new URL(url);
  const mod = parsedUrl.protocol === 'https:' ? require('https') : require('http');

  return new Promise((resolve, reject) => {
    const headers: Record<string, string> = {};
    if (init?.headers) {
      const h = init.headers;
      if (h instanceof Headers) {
        h.forEach((v, k) => { headers[k] = v; });
      } else if (typeof h === 'object') {
        Object.assign(headers, h);
      }
    }

    const options = {
      hostname: parsedUrl.hostname,
      port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
      path: parsedUrl.pathname + parsedUrl.search,
      method: init?.method || 'GET',
      headers,
      agent,
    };

    const req = mod.request(options, (res: any) => {
      const chunks: Buffer[] = [];
      res.on('data', (c: Buffer) => chunks.push(c));
      res.on('end', () => {
        const body = Buffer.concat(chunks);
        resolve(new Response(body, {
          status: res.statusCode || 502,
          statusText: res.statusMessage || '',
          headers: new Headers(res.headers || {}),
        }));
      });
    });

    req.on('error', reject);
    if (init?.signal) {
      init.signal.addEventListener('abort', () => req.destroy());
    }
    if (init?.body) {
      req.write(
        typeof init.body === 'string' ? init.body :
        init.body instanceof Buffer ? init.body :
        init.body instanceof ArrayBuffer ? Buffer.from(init.body) :
        Buffer.from(String(init.body))
      );
    }
    req.end();
  });
}

export async function testProxyConnection(
  proxyUrl: string,
  testUrl?: string
): Promise<{ ok: boolean; latency: number; info: string }> {
  const target = testUrl || 'http://pansou:80';
  const start = Date.now();
  try {
    const res = await proxiedFetch(target, {
      signal: AbortSignal.timeout(10000),
    }, proxyUrl);
    const latency = Date.now() - start;
    return { ok: true, latency, info: `连接成功 (${res.status})` };
  } catch (err: any) {
    return { ok: false, latency: Date.now() - start, info: `代理连接失败: ${err.message}` };
  }
}

// Legacy compat — no longer returns dispatcher, kept for type compatibility
export function createProxyDispatcher(proxyUrl?: string): { agent: any } | null {
  const agent = createProxyAgent(proxyUrl);
  return agent ? { agent } : null;
}
