'use strict';

/**
 * Mistral AI Provider (Default)
 * 
 * Pricing (April 2026):
 *   Large 3:  $0.50 / 1M input,  $1.50 / 1M output
 *   Small 4:  $0.15 / 1M input,  $0.60 / 1M output
 *   Medium:   $0.40 / 1M input,  $2.00 / 1M output
 */

const https = require('https');
const { URL } = require('url');

const DEFAULT_MODELS = {
  classification: 'mistral-small-latest',
  codeGeneration: 'mistral-large-latest',
  analysis: 'mistral-large-latest',
};

class MistralProvider {
  constructor(config) {
    this.apiKey = config.apiKey;
    this.baseUrl = config.baseUrl || 'https://api.mistral.ai/v1';
    this.models = Object.assign({}, DEFAULT_MODELS, config.model);
    this.temperature = config.temperature ?? 0.1;
    this.maxTokens = config.maxTokens ?? 4096;
    this.timeout = config.timeout ?? 30000;
  }

  /**
   * @param {Array<{role: string, content: string}>} messages
   * @param {object} options
   * @returns {Promise<string>}
   */
  async chat(messages, options = {}) {
    const model = options.model || this.models.codeGeneration;
    const body = {
      model,
      messages,
      temperature: options.temperature ?? this.temperature,
      max_tokens: options.maxTokens ?? this.maxTokens,
    };

    const response = await this._request('/chat/completions', body);

    if (!response.choices || !response.choices[0]) {
      throw new Error('Mistral API returned empty response');
    }

    return response.choices[0].message.content;
  }

  async _request(path, body) {
    const url = new URL(path, this.baseUrl);

    return new Promise((resolve, reject) => {
      const postData = JSON.stringify(body);

      const req = https.request(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${this.apiKey}`,
          'Content-Length': Buffer.byteLength(postData),
        },
        timeout: this.timeout,
      }, (res) => {
        let data = '';
        res.on('data', chunk => data += chunk);
        res.on('end', () => {
          if (res.statusCode >= 400) {
            reject(new Error(`Mistral API ${res.statusCode}: ${data.slice(0, 500)}`));
            return;
          }
          try {
            resolve(JSON.parse(data));
          } catch (e) {
            reject(new Error(`Failed to parse Mistral response: ${e.message}`));
          }
        });
      });

      req.on('timeout', () => {
        req.destroy();
        reject(new Error('Mistral API request timed out'));
      });

      req.on('error', reject);
      req.write(postData);
      req.end();
    });
  }
}

module.exports = MistralProvider;
