/**
 * with-openai.js — PGS Engine with real OpenAI providers
 *
 * Uses OpenAI's chat completions API for sweep/synthesis and their
 * embeddings API for query routing. Zero npm dependencies — uses
 * Node.js built-in fetch() directly.
 *
 * Requires: OPENAI_API_KEY environment variable
 *
 * Usage:
 *   OPENAI_API_KEY=sk-... node examples/with-openai.js
 */

'use strict';

const fs = require('fs');
const zlib = require('zlib');
const path = require('path');
const { PGSEngine } = require('../src');

// ─── API Key Check ───────────────────────────────────────────────────

const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
if (!OPENAI_API_KEY) {
  console.error('Error: OPENAI_API_KEY environment variable is required.');
  console.error('');
  console.error('  export OPENAI_API_KEY=sk-...');
  console.error('  node examples/with-openai.js');
  process.exit(1);
}

// ─── Provider Factories ──────────────────────────────────────────────

/**
 * Create an OpenAI-compatible LLM provider using fetch().
 *
 * @param {object} options
 * @param {string} options.apiKey - API key
 * @param {string} [options.baseURL='https://api.openai.com/v1'] - API base URL
 * @param {string} [options.model='gpt-4.1-mini'] - Model name
 * @returns {{generate: Function}}
 */
function createChatProvider({ apiKey, baseURL = 'https://api.openai.com/v1', model = 'gpt-4.1-mini' }) {
  return {
    generate: async ({ instructions, input, maxTokens = 4096, onChunk }) => {
      const response = await fetch(`${baseURL}/chat/completions`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${apiKey}`,
        },
        body: JSON.stringify({
          model,
          messages: [
            { role: 'system', content: instructions },
            { role: 'user', content: input },
          ],
          max_tokens: maxTokens,
        }),
      });

      if (!response.ok) {
        const err = await response.text();
        throw new Error(`OpenAI API error (${response.status}): ${err}`);
      }

      const data = await response.json();
      const content = data.choices?.[0]?.message?.content || '';
      return { content };
    }
  };
}

/**
 * Create an OpenAI embedding provider using fetch().
 *
 * @param {object} options
 * @param {string} options.apiKey - API key
 * @param {string} [options.model='text-embedding-3-small'] - Embedding model
 * @param {number} [options.dimensions=512] - Embedding dimensions
 * @returns {{embed: Function, dimensions: number}}
 */
function createEmbeddingProvider({ apiKey, model = 'text-embedding-3-small', dimensions = 512 }) {
  return {
    dimensions,
    embed: async (text) => {
      const response = await fetch('https://api.openai.com/v1/embeddings', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${apiKey}`,
        },
        body: JSON.stringify({
          model,
          input: text,
          dimensions,
        }),
      });

      if (!response.ok) {
        const err = await response.text();
        throw new Error(`OpenAI Embeddings error (${response.status}): ${err}`);
      }

      const data = await response.json();
      return data.data?.[0]?.embedding || null;
    }
  };
}

// ─── Load Brain ──────────────────────────────────────────────────────

console.log('Loading physics2 brain...');
const gz = fs.readFileSync(path.join(__dirname, 'data', 'physics2.json.gz'));
const data = JSON.parse(zlib.gunzipSync(gz).toString());
const graph = { nodes: data.nodes, edges: data.edges };

console.log(`Brain: ${data.metadata?.name || 'physics2'}`);
console.log(`Nodes: ${graph.nodes.length}, Edges: ${graph.edges.length}`);

// ─── Create Engine ───────────────────────────────────────────────────

const sweepProvider = createChatProvider({
  apiKey: OPENAI_API_KEY,
  model: 'gpt-4.1-mini',
});

const synthesisProvider = createChatProvider({
  apiKey: OPENAI_API_KEY,
  model: 'gpt-4.1-mini',
});

const embeddingProvider = createEmbeddingProvider({
  apiKey: OPENAI_API_KEY,
});

const engine = new PGSEngine({
  sweepProvider,
  synthesisProvider,
  embeddingProvider,
});

// ─── Run Query ───────────────────────────────────────────────────────

async function main() {
  const query = 'What are the most surprising findings in this research?';

  console.log(`\nQuery: "${query}"\n`);

  const startTime = Date.now();

  try {
    const result = await engine.execute(query, graph, {
      onEvent: (event) => {
        switch (event.type) {
          case 'partitioning':
            if (event.partitionCount) {
              console.log(`  [partition] ${event.nodeCount || '?'} nodes -> ${event.partitionCount} partitions`);
            }
            break;
          case 'routing':
            if (event.selectedCount) {
              console.log(`  [route]     ${event.selectedCount}/${event.totalCount} partitions selected`);
            }
            break;
          case 'sweeping':
            console.log(`  [sweep]     ${event.message}`);
            break;
          case 'sweep_complete':
            console.log(`  [sweep]     Partition ${event.partitionId} complete`);
            break;
          case 'synthesizing':
            console.log(`  [synth]     ${event.message}`);
            break;
          case 'complete':
            console.log(`  [done]      ${(event.elapsedMs / 1000).toFixed(1)}s`);
            break;
        }
      }
    });

    const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);

    console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
    console.log('  ANSWER');
    console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
    console.log(result.answer);

    console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
    console.log('  PGS METADATA');
    console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
    const pgs = result.metadata.pgs;
    console.log(`  Nodes:              ${pgs.totalNodes}`);
    console.log(`  Edges:              ${pgs.totalEdges}`);
    console.log(`  Total partitions:   ${pgs.totalPartitions}`);
    console.log(`  Swept partitions:   ${pgs.sweptPartitions}`);
    console.log(`  Successful sweeps:  ${pgs.successfulSweeps}`);
    console.log(`  PGS elapsed:        ${pgs.elapsed}`);
    console.log(`  Total elapsed:      ${elapsed}s`);
  } catch (err) {
    console.error(`\nError: ${err.message}`);
    process.exit(1);
  }
}

main().catch(err => {
  console.error(err);
  process.exit(1);
});
