import * as path from 'path';
import * as fs from 'fs';
export class PiAIModel {
    config;
    provider;
    constructor(config) {
        this.config = config;
        this.provider = config.provider;
    }
    async chat(message, context) {
        const systemPrompt = this.buildSystemPrompt(context);
        const messages = [
            { role: 'system', content: systemPrompt },
            { role: 'user', content: message }
        ];
        try {
            const response = await this.generateText({
                messages,
                temperature: 0.8
            });
            return { reply: response };
        }
        catch (error) {
            console.error('PiAI chat error:', error);
            return { reply: '抱歉，AI服务暂时不可用。' };
        }
    }
    async summarize(text, context) {
        const prompt = this.buildSummarizePrompt(text, context);
        try {
            const response = await this.generateText({
                messages: [
                    { role: 'system', content: 'You are a professional document summarizer.' },
                    { role: 'user', content: prompt }
                ],
                temperature: 0.7
            });
            const qualityScore = this.estimateQuality(text, response);
            return { summary: response, qualityScore };
        }
        catch (error) {
            console.error('PiAI summarize error:', error);
            return {
                summary: text.substring(0, 500) + '...',
                qualityScore: 0.5
            };
        }
    }
    async improveContent(content, requirements, context) {
        const prompt = this.buildImprovePrompt(content, requirements, context);
        try {
            const response = await this.generateText({
                messages: [
                    { role: 'system', content: 'You are a professional document editor and improver.' },
                    { role: 'user', content: prompt }
                ],
                temperature: 0.8
            });
            return response;
        }
        catch (error) {
            console.error('PiAI improve error:', error);
            return content;
        }
    }
    async generateText(options) {
        const { messages, temperature = 0.7, maxTokens = 4096 } = options;
        switch (this.provider) {
            case 'openai':
            case 'minimax':
                return this.callOpenAI(messages, temperature, maxTokens);
            case 'anthropic':
                return this.callAnthropic(messages, temperature, maxTokens);
            case 'ollama':
                return this.callOllama(messages, temperature);
            case 'openrouter':
                return this.callOpenRouter(messages, temperature, maxTokens);
            case 'gemini':
                return this.callGemini(messages, temperature, maxTokens);
            case 'local':
                return this.callLocal(messages, temperature);
            default:
                throw new Error(`Unsupported provider: ${this.provider}`);
        }
    }
    getApiKey() {
        return this.config.apiKey || this.getEnvApiKey();
    }
    getEnvApiKey() {
        const envVars = {
            openai: process.env.OPENAI_API_KEY || '',
            anthropic: process.env.ANTHROPIC_API_KEY || '',
            ollama: '',
            openrouter: process.env.OPENROUTER_API_KEY || '',
            gemini: process.env.GEMINI_API_KEY || '',
            minimax: process.env.MINIMAX_API_KEY || '',
            local: ''
        };
        return envVars[this.provider] || '';
    }
    getBaseUrl() {
        if (this.config.baseUrl) {
            return this.config.baseUrl;
        }
        // 允许通过 OPENAI_BASE_URL 等环境变量覆盖默认 base URL
        const baseUrls = {
            openai: process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1',
            anthropic: 'https://api.anthropic.com/v1',
            ollama: process.env.OLLAMA_BASE_URL || 'http://localhost:11434',
            openrouter: process.env.OPENROUTER_BASE_URL || 'https://openrouter.ai/api/v1',
            gemini: 'https://generativelanguage.googleapis.com/v1beta',
            minimax: process.env.MINIMAX_BASE_URL || 'https://api.minimaxi.com/v1',
            local: 'http://localhost:11434'
        };
        return baseUrls[this.provider];
    }
    mapModel() {
        const modelMap = {
            openai: this.config.model || process.env.OPENAI_MODEL || 'gpt-4',
            anthropic: this.config.model || 'claude-3-5-sonnet-20241022',
            ollama: this.config.model || 'llama3.2',
            openrouter: this.config.model || 'anthropic/claude-3.5-sonnet',
            gemini: this.config.model || 'gemini-2.0-flash',
            minimax: this.config.model || process.env.MINIMAX_MODEL || 'MiniMax-M2.7',
            local: this.config.model || 'llama3.2'
        };
        return modelMap[this.provider];
    }
    async callOpenAI(messages, temperature, maxTokens) {
        const apiKey = this.getApiKey();
        if (!apiKey) {
            throw new Error('OPENAI_API_KEY not set');
        }
        const response = await fetch(`${this.getBaseUrl()}/chat/completions`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${apiKey}`
            },
            body: JSON.stringify({
                model: this.mapModel(),
                messages,
                temperature,
                max_tokens: maxTokens
            })
        });
        if (!response.ok) {
            throw new Error(`OpenAI API error: ${response.status}`);
        }
        const data = await response.json();
        return data.choices?.[0]?.message?.content || '';
    }
    async callAnthropic(messages, temperature, maxTokens) {
        const apiKey = this.getApiKey();
        if (!apiKey) {
            throw new Error('ANTHROPIC_API_KEY not set');
        }
        const systemMessage = messages.find(m => m.role === 'system')?.content || '';
        const userMessages = messages.filter(m => m.role !== 'system');
        const response = await fetch(`${this.getBaseUrl()}/messages`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'x-api-key': apiKey,
                'anthropic-version': '2023-06-01',
                'anthropic-dangerous-direct-browser-access': 'true'
            },
            body: JSON.stringify({
                model: this.mapModel(),
                messages: userMessages,
                system: systemMessage,
                temperature,
                max_tokens: maxTokens
            })
        });
        if (!response.ok) {
            throw new Error(`Anthropic API error: ${response.status}`);
        }
        const data = await response.json();
        return data.content?.[0]?.text || '';
    }
    async callOllama(messages, temperature) {
        const response = await fetch(`${this.getBaseUrl()}/api/chat`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                model: this.mapModel(),
                messages,
                temperature,
                stream: false
            })
        });
        if (!response.ok) {
            throw new Error(`Ollama API error: ${response.status}`);
        }
        const data = await response.json();
        return data.message?.content || '';
    }
    async callOpenRouter(messages, temperature, maxTokens) {
        const apiKey = this.getApiKey();
        if (!apiKey) {
            throw new Error('OPENROUTER_API_KEY not set');
        }
        const response = await fetch(`${this.getBaseUrl()}/chat/completions`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${apiKey}`,
                'HTTP-Referer': 'https://openclaw.ai',
                'X-Title': 'OpenClaw'
            },
            body: JSON.stringify({
                model: this.mapModel(),
                messages,
                temperature,
                max_tokens: maxTokens
            })
        });
        if (!response.ok) {
            throw new Error(`OpenRouter API error: ${response.status}`);
        }
        const data = await response.json();
        return data.choices?.[0]?.message?.content || '';
    }
    async callGemini(messages, temperature, maxTokens) {
        const apiKey = this.getApiKey();
        if (!apiKey) {
            throw new Error('GEMINI_API_KEY not set');
        }
        const contents = messages
            .filter(m => m.role !== 'system')
            .map(m => ({
            role: m.role === 'assistant' ? 'model' : 'user',
            parts: [{ text: m.content }]
        }));
        const systemInstruction = messages.find(m => m.role === 'system')?.content;
        const response = await fetch(`${this.getBaseUrl()}/models/${this.mapModel()}:generateContent?key=${apiKey}`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                contents,
                systemInstruction: systemInstruction ? { parts: [{ text: systemInstruction }] } : undefined,
                generationConfig: {
                    temperature,
                    maxOutputTokens: maxTokens
                }
            })
        });
        if (!response.ok) {
            throw new Error(`Gemini API error: ${response.status}`);
        }
        const data = await response.json();
        return data.candidates?.[0]?.content?.parts?.[0]?.text || '';
    }
    async callLocal(messages, temperature) {
        return this.callOllama(messages, temperature);
    }
    buildSystemPrompt(context) {
        const envDetails = this.getEnvironmentDetails();
        return `You are a friendly AI assistant in a P2P document collaboration network.

## User Working Directory
${context || process.cwd()}

## Environment
${envDetails}`;
    }
    getEnvironmentDetails() {
        return `
## Available Workflows
- read - Read documents
- summarize - Summarize documents  
- improve - Improve documents
- collaborate - Multi-agent collaboration
- query - Query status
- report - Generate reports

## System Capabilities
- Document processing (Markdown, Text, PDF, DOCX)
- Multi-agent collaboration (P2P network)
- Workflow engine (constraint layer)
- Quality assessment and auto-send

## Current Time
${new Date().toISOString()}`;
    }
    buildSummarizePrompt(text, context) {
        const maxLength = 8000;
        const truncatedText = text.length > maxLength ? text.substring(0, maxLength) + '...' : text;
        let prompt = `Please generate a concise and accurate summary for the following document:

${truncatedText}

Please output in the following format:
## Summary
[Write summary here]

## Quality Self-Assessment
[Score 1-10, with reasoning]`;
        if (context) {
            prompt = `Context: ${context}

${prompt}`;
        }
        return prompt;
    }
    buildImprovePrompt(content, requirements, context) {
        const maxLength = 8000;
        const truncatedContent = content.length > maxLength ? content.substring(0, maxLength) + '...' : content;
        let prompt = `Please improve the document according to the following requirements:

Requirements: ${requirements}

Original Document:
${truncatedContent}

Please output only the improved document without additional explanation.`;
        if (context) {
            prompt = `Context: ${context}

${prompt}`;
        }
        return prompt;
    }
    estimateQuality(original, summary) {
        const coverageRatio = summary.length / Math.max(original.length, 1);
        const hasKeyPoints = /\d+\s*[.。]/.test(summary);
        const decentLength = summary.length > 100 && summary.length < original.length * 0.5;
        let score = 0.5;
        if (coverageRatio > 0.1 && coverageRatio < 0.5)
            score += 0.2;
        if (hasKeyPoints)
            score += 0.15;
        if (decentLength)
            score += 0.15;
        return Math.min(1, score);
    }
    async shouldAutoSend(qualityScore, threshold = 0.7) {
        return qualityScore >= threshold;
    }
}
let modelInstance = null;
function detectProvider() {
    // 首先检查配置文件（优先级最高）
    try {
        const configPath = path.join(process.env.HOME || '/tmp', '.bolloon', 'llm-config.json');
        const configData = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
        if (configData.activeProvider && configData.providers[configData.activeProvider]) {
            console.log('[PiAIModel] Detected provider from config:', configData.activeProvider);
            return configData.activeProvider;
        }
    }
    catch { }
    // 然后检查环境变量
    if (process.env.OPENAI_API_KEY)
        return 'openai';
    if (process.env.ANTHROPIC_API_KEY)
        return 'anthropic';
    if (process.env.OPENROUTER_API_KEY)
        return 'openrouter';
    if (process.env.GEMINI_API_KEY)
        return 'gemini';
    if (process.env.OLLAMA_BASE_URL)
        return 'ollama';
    if (process.env.MINIMAX_API_KEY)
        return 'minimax';
    return 'openai';
}
function detectModel(provider) {
    const defaults = {
        openai: 'gpt-4',
        anthropic: 'claude-3-5-sonnet-20241022',
        ollama: 'llama3.2',
        openrouter: 'anthropic/claude-3.5-sonnet',
        gemini: 'gemini-2.0-flash',
        minimax: 'MiniMax-M2.7',
        local: 'llama3.2'
    };
    return defaults[provider];
}
export function initPiAI(config = {}) {
    const provider = config.provider || detectProvider();
    const model = config.model || detectModel(provider);
    console.log('[PiAIModel] Initializing with provider:', provider, 'model:', model);
    // 如果没有提供 apiKey，从配置文件读取
    let apiKey = config.apiKey;
    if (!apiKey) {
        try {
            const configPath = path.join(process.env.HOME || '/tmp', '.bolloon', 'llm-config.json');
            const configData = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
            const providerConfig = configData.providers[provider];
            if (providerConfig?.apiKey) {
                apiKey = providerConfig.apiKey;
                console.log('[PiAIModel] Loaded apiKey from config for', provider);
            }
        }
        catch (e) {
            console.log('[PiAIModel] Error reading apiKey from config:', e);
        }
    }
    modelInstance = new PiAIModel({
        provider,
        apiKey,
        baseUrl: config.baseUrl,
        model
    });
    console.log('[PiAIModel] Model instance created, provider:', provider);
    return modelInstance;
}
export function getModel() {
    if (!modelInstance) {
        throw new Error('PiAI not initialized. Call initPiAI first.');
    }
    return modelInstance;
}
export function isModelAvailable() {
    return modelInstance !== null;
}
export function getMinimax() {
    return getModel();
}
export function initMinimax(config = {}) {
    return initPiAI(config);
}
export { PiAIModel as MinimaxLLM };
