import type Config from '../types/config';
import type GPTAnswer from '../types/gpt-answer';
import getContentWithHistory from './get-content-with-history';
import OpenAI from 'openai';
import { fixeO } from '../utils/fixe-o';
import { QuestionSchemas } from './utils/question-schemas';
import { MoodleQuestionType, MoodleQuestionResponse } from '../types/question-types';

/**
 * Get the response from chatGPT api
 * @param config
 * @param question
 * @returns
 */
async function getChatGPTResponse(
  config: Config,
  questionElement: HTMLElement,
  question: string
): Promise<GPTAnswer> {
  const controller = new AbortController();
  const timeoutControler = setTimeout(() => controller.abort(), (config.timeoutValue || 20) * 1000);

  // Get the content to send to chatgpt
  // Including the instructions to the AI, the images as base64 if needed,
  // the question and the past conversation if history is set to true
  const contentHandler = await getContentWithHistory(config, questionElement, question);

  const client = new OpenAI({
    apiKey: config.apiKey,
    baseURL: config.baseURL,
    project: config.projectId,
    dangerouslyAllowBrowser: true
  });

  const questionType = contentHandler.query
    ? contentHandler.query.question_type
    : MoodleQuestionType.UNKNOWN;
  const targetSchema: MoodleQuestionResponse =
    questionType !== MoodleQuestionType.UNKNOWN ? QuestionSchemas[questionType] : undefined;

  const requestPayload: any = {
    model: config.model,
    messages: contentHandler.messages.map(msg => ({ ...msg })),
    max_completion_tokens: config.maxTokens || 2000
  };

  // Use the modern json_schema structured output when a schema is available.
  // The model is guaranteed to return schema-valid JSON — no prompt hacks needed.
  if (targetSchema) {
    requestPayload.response_format = {
      type: 'json_schema',
      json_schema: targetSchema
    };
  }

  const req = await client.chat.completions.create(fixeO(config.model, requestPayload), {
    signal: config.timeout ? controller.signal : null
  });

  clearTimeout(timeoutControler);

  const rawResponse = req.choices[0].message.content ?? '';

  let structuredResponse: MoodleQuestionResponse | null = null;
  if (targetSchema && rawResponse) {
    try {
      structuredResponse = JSON.parse(rawResponse);
    } catch (e) {
      console.error('Failed to parse structured JSON response', e);
    }
  }

  // Save the response into the history
  if (typeof contentHandler.saveResponse === 'function') {
    contentHandler.saveResponse(rawResponse);
  }

  return {
    questionQuery: contentHandler.query,
    response: structuredResponse,
    rawResponse: rawResponse
  };
}

export default getChatGPTResponse;
