/**
 * Сервис ИИ-чата: системный промпт, загрузка истории, вызов ai.iieasy.ru (OpenAI-совместимый API), цикл tool_calls.
 */

const axios = require('axios');
const { getToolsSchema, runTool } = require('./aiToolsRegistry');

const AI_CHAT_URL = process.env.AI_CHAT_URL || 'https://ai.iieasy.ru/v1/chat/completions';
const AI_API_KEY = process.env.AI_API_KEY || '';
const AI_MODEL = process.env.AI_MODEL || 'gpt-4o-mini';
const MAX_TOOL_ITERATIONS = 5;
const HISTORY_MESSAGES_LIMIT = 25;
const REQUEST_TIMEOUT_MS = 60000;

function buildSystemPrompt(userContext) {
  const { userName = 'Пользователь', role = '', allowedSections = [] } = userContext;
  const sections = Array.isArray(allowedSections) && allowedSections.length ? allowedSections.join(', ') : 'не заданы';
  return `Ты помощник в системе управления МКД (многоквартирными домами). Пользователь: ${userName}, роль: ${role}. Разрешённые разделы: ${sections}.
Задавай уточняющие вопросы, если данных недостаточно для действия. Для выполнения действий в программе (список домов, создание счёта, заявки и т.д.) используй только вызов инструментов. Отвечай кратко и по делу на русском.`;
}

/**
 * Преобразовать сообщения из БД в формат OpenAI messages[] (role, content; для assistant с tool_calls — role, content, tool_calls).
 */
function dbMessagesToOpenAI(rows) {
  const messages = [];
  for (const row of rows) {
    const msg = { role: row.role, content: row.content || '' };
    if (row.toolCallsJson && Array.isArray(row.toolCallsJson) && row.toolCallsJson.length) {
      msg.tool_calls = row.toolCallsJson;
    }
    messages.push(msg);
  }
  return messages;
}

/**
 * Вызвать ИИ (OpenAI-compatible chat completions).
 * @param {object} options
 * @param {Array} options.messages — OpenAI format
 * @param {Array} options.tools — getToolsSchema()
 * @returns {Promise<{ content?: string, tool_calls?: Array }>}
 */
async function callChatCompletion({ messages, tools, aiChatUrl, aiApiKey }) {
  const url = aiChatUrl != null && aiChatUrl !== '' ? aiChatUrl : AI_CHAT_URL;
  const key = aiApiKey !== undefined ? aiApiKey : AI_API_KEY;
  const headers = {
    'Content-Type': 'application/json'
  };
  if (key) {
    headers['Authorization'] = `Bearer ${key}`;
  }
  const body = {
    model: AI_MODEL,
    messages,
    tools: tools && tools.length ? tools : undefined,
    tool_choice: tools && tools.length ? 'auto' : undefined,
    max_tokens: 2048,
    temperature: 0.3
  };
  const res = await axios.post(url, body, {
    headers,
    timeout: REQUEST_TIMEOUT_MS,
    validateStatus: (s) => s === 200
  });
  const choice = res.data.choices && res.data.choices[0];
  if (!choice) {
    throw new Error('Пустой ответ от ИИ');
  }
  const delta = choice.message || {};
  return {
    content: delta.content || null,
    tool_calls: delta.tool_calls || null
  };
}

/**
 * Обработать один раунд чата: вызов ИИ, при наличии tool_calls — выполнить инструменты и вернуть обновлённые messages + флаг «нужен ещё раунд».
 * collectedToolResults — массив, в который пушатся результаты вызовов { toolName, success, error? } для ответа клиенту.
 */
async function oneRound({ messages, tools, user, runToolContext, collectedToolResults, aiChatUrl, aiApiKey }) {
  const response = await callChatCompletion({ messages, tools, aiChatUrl, aiApiKey });
  const assistantContent = response.content ? response.content.trim() : '';
  const toolCalls = response.tool_calls;

  const nextMessages = [...messages];

  if (toolCalls && toolCalls.length) {
    const assistantMsg = {
      role: 'assistant',
      content: assistantContent || '(вызов инструментов)',
      tool_calls: toolCalls
    };
    nextMessages.push(assistantMsg);

    for (const tc of toolCalls) {
      const name = tc.function && tc.function.name;
      let args = {};
      try {
        if (tc.function && tc.function.arguments) {
          args = typeof tc.function.arguments === 'string' ? JSON.parse(tc.function.arguments) : tc.function.arguments;
        }
      } catch (e) {
        args = {};
      }
      const result = await runTool(name, args, user, runToolContext);
      if (collectedToolResults) {
        collectedToolResults.push({ toolName: name, success: result.success, error: result.error });
      }
      const toolResult = {
        role: 'tool',
        tool_call_id: tc.id,
        content: JSON.stringify(result)
      };
      nextMessages.push(toolResult);
    }
    return { messages: nextMessages, done: false, finalContent: null };
  }

  return { messages: nextMessages, done: true, finalContent: assistantContent };
}

/**
 * Получить ответ ИИ по истории и новому сообщению пользователя. Выполняет tool_calls в цикле (до MAX_TOOL_ITERATIONS).
 * @param {object} options
 * @param {Function} options.query — (sql, params) => Promise<rows>
 * @param {number} options.conversationId
 * @param {string} options.newUserMessage
 * @param {object} options.user — req.user
 * @param {object} options.userContext — { userName, role, allowedSections } для системного промпта
 * @param {object} options.runToolContext — { baseUrl, apiPrefix, getTokenForUser }
 * @param {string} [options.aiChatUrl] — URL ИИ (из панели или env)
 * @param {string} [options.aiApiKey] — API key (токен)
 * @returns {Promise<{ assistantMessage: string, toolResults: Array }>}
 */
async function getAIResponse({ query, conversationId, newUserMessage, user, userContext, runToolContext, aiChatUrl, aiApiKey }) {
  const tools = getToolsSchema();
  const systemPrompt = buildSystemPrompt(userContext);

  const rows = await query(
    `SELECT role, content, tool_calls_json AS "toolCallsJson"
     FROM ai_messages
     WHERE conversation_id = $1
     ORDER BY created_at ASC
     LIMIT $2`,
    [conversationId, HISTORY_MESSAGES_LIMIT]
  );
  const history = dbMessagesToOpenAI(rows);
  const messages = [
    { role: 'system', content: systemPrompt },
    ...history,
    { role: 'user', content: newUserMessage }
  ];

  let currentMessages = messages;
  let iterations = 0;
  let finalContent = '';
  const toolResults = [];

  while (iterations < MAX_TOOL_ITERATIONS) {
    const round = await oneRound({
      messages: currentMessages,
      tools,
      user,
      runToolContext,
      collectedToolResults: toolResults,
      aiChatUrl,
      aiApiKey
    });
    currentMessages = round.messages;
    if (round.done) {
      finalContent = round.finalContent || '';
      break;
    }
    iterations++;
  }

  if (!finalContent && iterations >= MAX_TOOL_ITERATIONS) {
    finalContent = 'Достигнут лимит шагов. Попробуйте упростить запрос.';
  }

  return { assistantMessage: finalContent, toolResults };
}

module.exports = {
  buildSystemPrompt,
  getAIResponse,
  callChatCompletion
};
