import https from 'https';
import http from 'http';
import { URL } from 'url';

/**
 * Universal Native HTTP Request Helper (zero extra external dependencies)
 */
function makeHttpRequest(targetUrl: string, method: string, headers: Record<string, string>, body?: string): Promise<any> {
  return new Promise((resolve, reject) => {
    const parsedUrl = new URL(targetUrl);
    const options = {
      hostname: parsedUrl.hostname,
      port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
      path: parsedUrl.pathname + parsedUrl.search,
      method,
      headers: {
        'Content-Type': 'application/json',
        ...headers,
      },
    };

    const client = parsedUrl.protocol === 'https:' ? https : http;
    const req = client.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => (data += chunk));
      res.on('end', () => {
        if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
          try {
            resolve(JSON.parse(data));
          } catch {
            resolve(data);
          }
        } else {
          reject(new Error(`HTTP ${res.statusCode}: ${data}`));
        }
      });
    });

    req.on('error', (err) => reject(err));
    if (body) {
      req.write(body);
    }
    req.end();
  });
}

export class AIService {
  private static getGeminiKey(): string | undefined {
    return process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY;
  }

  private static getOpenAIKey(): string | undefined {
    return process.env.OPENAI_API_KEY;
  }

  /**
   * Check if any real AI provider is configured
   */
  public static isAIConfigured(): boolean {
    return !!(this.getGeminiKey() || this.getOpenAIKey());
  }

  /**
   * Generate raw text using Gemini or OpenAI
   */
  public static async generateText(
    prompt: string,
    systemInstruction?: string,
    temperature = 0.7
  ): Promise<string> {
    const geminiKey = this.getGeminiKey();
    const openaiKey = this.getOpenAIKey();

    // 1. Try Google Gemini API
    if (geminiKey) {
      try {
        const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${geminiKey}`;
        const payload = {
          contents: [
            {
              role: 'user',
              parts: [{ text: `${systemInstruction ? `[System Instructions: ${systemInstruction}]\n\n` : ''}${prompt}` }],
            },
          ],
          generationConfig: {
            temperature,
            maxOutputTokens: 2048,
          },
        };

        const response = await makeHttpRequest(url, 'POST', {}, JSON.stringify(payload));
        const text = response?.candidates?.[0]?.content?.parts?.[0]?.text;
        if (text) return text.trim();
      } catch (err: any) {
        console.warn('Gemini API request failed, trying next provider:', err.message);
      }
    }

    // 2. Try OpenAI API
    if (openaiKey) {
      try {
        const url = 'https://api.openai.com/v1/chat/completions';
        const payload = {
          model: 'gpt-4o-mini',
          messages: [
            ...(systemInstruction ? [{ role: 'system', content: systemInstruction }] : []),
            { role: 'user', content: prompt },
          ],
          temperature,
          max_tokens: 2048,
        };

        const response = await makeHttpRequest(
          url,
          'POST',
          { Authorization: `Bearer ${openaiKey}` },
          JSON.stringify(payload)
        );
        const text = response?.choices?.[0]?.message?.content;
        if (text) return text.trim();
      } catch (err: any) {
        console.warn('OpenAI API request failed:', err.message);
      }
    }

    // 3. Resilient heuristic fallback
    return this.fallbackTextGenerator(prompt);
  }

  /**
   * Generate structured JSON from Gemini or OpenAI
   */
  public static async generateJSON<T>(
    prompt: string,
    systemInstruction?: string,
    schemaHint?: string
  ): Promise<T> {
    const enrichedSystem = `${systemInstruction || 'You are an expert Indian literature and e-commerce AI.'}\nRespond ONLY in valid RFC-8259 JSON format with no markdown ticks or preamble.${schemaHint ? ` Expected JSON structure:\n${schemaHint}` : ''}`;

    const text = await this.generateText(prompt, enrichedSystem, 0.2);

    try {
      const cleanJson = text.replace(/```json/gi, '').replace(/```/g, '').trim();
      return JSON.parse(cleanJson) as T;
    } catch {
      // Find outermost JSON brackets if response contained additional text
      const match = text.match(/\{[\s\S]*\}|\[[\s\S]*\]/);
      if (match) {
        return JSON.parse(match[0]) as T;
      }
      throw new Error(`AI generated non-JSON response: ${text.slice(0, 150)}...`);
    }
  }

  /**
   * Generate Vector Embeddings (Gemini text-embedding-004 or OpenAI text-embedding-3-small)
   */
  public static async generateEmbedding(text: string): Promise<number[]> {
    const geminiKey = this.getGeminiKey();
    const openaiKey = this.getOpenAIKey();

    if (geminiKey) {
      try {
        const url = `https://generativelanguage.googleapis.com/v1beta/models/text-embedding-004:embedContent?key=${geminiKey}`;
        const payload = {
          model: 'models/text-embedding-004',
          content: { parts: [{ text: text.slice(0, 2048) }] },
        };
        const response = await makeHttpRequest(url, 'POST', {}, JSON.stringify(payload));
        const values = response?.embedding?.values;
        if (Array.isArray(values) && values.length > 0) return values;
      } catch (err: any) {
        console.warn('Gemini embedding failed, falling back:', err.message);
      }
    }

    if (openaiKey) {
      try {
        const url = 'https://api.openai.com/v1/embeddings';
        const payload = {
          model: 'text-embedding-3-small',
          input: text.slice(0, 2048),
        };
        const response = await makeHttpRequest(
          url,
          'POST',
          { Authorization: `Bearer ${openaiKey}` },
          JSON.stringify(payload)
        );
        const values = response?.data?.[0]?.embedding;
        if (Array.isArray(values) && values.length > 0) return values;
      } catch (err: any) {
        console.warn('OpenAI embedding failed:', err.message);
      }
    }

    // Heuristic 64-dimensional semantic hash vector
    return this.generateDeterministicVector(text, 64);
  }

  /**
   * Calculate Cosine Similarity between two vector embeddings
   */
  public static cosineSimilarity(vecA: number[], vecB: number[]): number {
    if (!vecA.length || !vecB.length || vecA.length !== vecB.length) return 0;
    let dotProduct = 0;
    let normA = 0;
    let normB = 0;
    for (let i = 0; i < vecA.length; i++) {
      dotProduct += vecA[i] * vecB[i];
      normA += vecA[i] * vecA[i];
      normB += vecB[i] * vecB[i];
    }
    if (normA === 0 || normB === 0) return 0;
    return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
  }

  /**
   * Deterministic Term-Frequency vector generator for offline fallback
   */
  private static generateDeterministicVector(text: string, dimensions = 64): number[] {
    const vector = new Array(dimensions).fill(0);
    const clean = text.toLowerCase().replace(/[^a-z0-9\s]/g, '');
    const tokens = clean.split(/\s+/).filter(Boolean);

    tokens.forEach((token, index) => {
      let hash = 0;
      for (let i = 0; i < token.length; i++) {
        hash = (hash << 5) - hash + token.charCodeAt(i);
        hash |= 0;
      }
      const dim = Math.abs(hash) % dimensions;
      vector[dim] += 1 / (index + 1);
    });

    // Normalize
    const magnitude = Math.sqrt(vector.reduce((sum, val) => sum + val * val, 0));
    return magnitude > 0 ? vector.map((v) => v / magnitude) : vector;
  }

  /**
   * Heuristic fallback generator when no cloud AI key is configured
   */
  private static fallbackTextGenerator(prompt: string): string {
    const p = prompt.toLowerCase();
    if (p.includes('description') || p.includes('synopsis')) {
      return `This distinguished volume presents an authoritative critical edition and commentary on classical Indian literature, philology, and philosophy. Carefully curated for scholars, collectors, and sincere seekers of knowledge, it features meticulous translation, historical contextualization, and exhaustive thematic appendices.`;
    }
    if (p.includes('seo') || p.includes('keywords')) {
      return `Indian books, classical Sanskrit literature, Vedic philosophy, Indology, sacred scriptures, English translations, rare Indian manuscripts.`;
    }
    return `Indian Books Worldwide provides authentic Indian literature, Sanskrit scriptures, indology commentaries, and academic publications with worldwide insured delivery.`;
  }
}
