
import { KnowledgeFile, Message, Role, Language, AppSettings, ModelConfig } from "../types";
import { ragService } from './ragService';

const buildSystemInstruction = (files: KnowledgeFile[], settings: AppSettings, langInstruction: string) => {
  const fileNames = files.map(f => f.name).join(", ");
  return `
    You are an intelligent knowledge base assistant operating as a RAG system.
    
    System Configuration:
    - Retrieval: Top ${settings.topK} chunks, Rerank: ${settings.enableRerank ? 'Enabled' : 'Disabled'}
    - Knowledge Base Files: ${fileNames}
    
    You have access to the content of these files in your context.
    
    Your goal is to answer user questions primarily based on the content of these files.
    
    Strict Citation Rules:
    1. Whenever you use information from a file, you MUST cite the source filename at the end of the sentence or paragraph.
    2. Citation format: [filename.extension].
    3. If the answer is not found in the files, state so clearly.
    4. ${langInstruction}
  `;
};

// --- OpenAI Compatible Implementation ---
const callOpenAICompatible = async (
  currentPrompt: string,
  files: KnowledgeFile[],
  history: Message[],
  modelConfig: ModelConfig,
  settings: AppSettings,
  systemInstruction: string,
  apiKey: string
): Promise<string> => {
  if (!modelConfig.baseUrl) throw new Error("Base URL is required");

  // Construct OpenAI format messages
  const messages: any[] = [
    { role: "system", content: systemInstruction }
  ];

  // Add history
  history.forEach(msg => {
    messages.push({
      role: msg.role === Role.USER ? "user" : "assistant",
      content: msg.text
    });
  });

  // Current User Message Construction (Supports Vision)
  const contentParts: any[] = [];

  // 1. Add Text Prompt
  contentParts.push({ type: "text", text: currentPrompt });

  // 2. Add Images/Files
  files.forEach((file) => {
    if (file.type.startsWith("image/") && modelConfig.type === "vision") {
      contentParts.push({
        type: "image_url",
        image_url: {
          url: `data:${file.type};base64,${file.content}`
        }
      });
    } else {
      // For non-image files or if vision is not supported, append as text
      try {
        const decodedText = atob(file.content);
        contentParts.push({
          type: "text",
          text: `\n--- Context from file: ${file.name} ---\n${decodedText.substring(0, 10000)}... (truncated)\n`
        });
      } catch (e) {
        contentParts.push({
          type: "text",
          text: `\n[File attached: ${file.name} (${file.type}) - Content processing skipped]\n`
        });
      }
    }
  });

  messages.push({ role: "user", content: contentParts });

  const response = await fetch(`${modelConfig.baseUrl}/chat/completions`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${apiKey}`
    },
    body: JSON.stringify({
      model: modelConfig.modelId,
      messages: messages,
      temperature: settings.temperature,
      max_tokens: settings.maxTokens,
      stream: false
    })
  });

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

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


export const generateResponse = async (
  currentPrompt: string,
  files: KnowledgeFile[],
  history: Message[],
  language: Language,
  modelConfig: ModelConfig,
  settings: AppSettings,
  authToken?: string,
  onSearchStart?: () => void,
  onSearchComplete?: (results: any) => void
): Promise<string> => {

  // 1. Resolve API Key: Use model specific key
  let apiKey = modelConfig.apiKey;

  console.log('Model config:', modelConfig);
  console.log('API Key present:', !!apiKey);

  const langInstructionMap: Record<Language, string> = {
    zh: "请始终使用中文回答。",
    en: "Please always answer in English.",
    ja: "常に日本語で答えてください。"
  };
  const langInstruction = langInstructionMap[language];

  // RAG検索（知識ベースファイルがある場合）
  let ragPrompt = currentPrompt;
  let ragSources: string[] = [];

  if (files.length > 0 && authToken) {
    try {
      onSearchStart?.();
      console.log('Starting RAG search with prompt:', currentPrompt);

      const ragResponse = await ragService.search(currentPrompt, {
        ...settings,
        language
      }, authToken);

      console.log('RAG search response:', ragResponse);

      if (ragResponse && ragResponse.hasRelevantContent) {
        ragPrompt = ragResponse.ragPrompt;
        ragSources = ragResponse.sources;
        console.log('Using RAG enhanced prompt');
      } else {
        console.log('No relevant content found, using original prompt');
      }

      onSearchComplete?.(ragResponse?.searchResults || []);
    } catch (error) {
      console.warn('RAG search failed, using original prompt:', error);
      onSearchComplete?.([]);
    } finally {
      // 検索ステータスがリセットされていることを確認
      setTimeout(() => {
        onSearchComplete?.([]);
      }, 100);
    }
  }

  const systemInstruction = buildSystemInstruction(files, settings, langInstruction);

  try {
    // APIキーはオプションです - ローカルモデルを許可します
    // --- OpenAI Compatible API Logic ---
    return await callOpenAICompatible(
      ragPrompt,
      files,
      history,
      modelConfig,
      settings,
      systemInstruction,
      apiKey || "ollama",
    );
  } catch (error: any) {
    console.error("AI Service Error:", error);

    // より詳細なエラー情報を提供
    if (error.name === 'TypeError' && error.message.includes('fetch')) {
      throw new Error('ネットワーク接続に失敗しました。サーバーの状態を確認してください');
    }

    throw new Error(error.message || "API_ERROR");
  }
};
