import {
    AzureOpenAIProvider,
    createFallbackChain,
    GeminiProvider,
    OpenAIProvider,
    PerplexityProvider,
    type LLMProvider,
} from '@bytelyst/llm';
import { config } from '../config/index.js';
import logger from '../utils/logger.js';

export type AIProvider = 'openai' | 'perplexity' | 'gemini';

export interface AIProviderHealth {
    provider: AIProvider;
    configured: boolean;
    model: string;
    inFallbackList: boolean;
    fallbackIndex: number | null;
    status: 'configured' | 'missing_key' | 'ok' | 'error';
    message: string;
}

interface ProviderEntry {
    name: AIProvider;
    make: () => LLMProvider;
    defaultModel: string;
}

function resolveModel(provider: AIProvider): string {
    switch (provider) {
        case 'perplexity':
            return config.AI.MODEL.includes('sonar') ? config.AI.MODEL : 'sonar';
        case 'openai':
            return config.AI.MODEL.includes('gpt') ? config.AI.MODEL : 'gpt-4o-mini';
        case 'gemini':
            return config.AI.MODEL.includes('gemini') ? config.AI.MODEL : 'gemini-1.5-flash';
    }
}

function makeOpenAIProvider(): LLMProvider {
    // Prefer Azure OpenAI when endpoint + key + deployment are all configured
    if (config.AZURE_OPENAI_ENDPOINT && config.AZURE_OPENAI_KEY && config.AZURE_OPENAI_DEPLOYMENT) {
        return new AzureOpenAIProvider({
            endpoint: config.AZURE_OPENAI_ENDPOINT,
            apiKey: config.AZURE_OPENAI_KEY,
            deployment: config.AZURE_OPENAI_DEPLOYMENT,
        });
    }
    return new OpenAIProvider({ apiKey: config.AI.OPENAI_API_KEY, model: resolveModel('openai') });
}

const PROVIDER_REGISTRY: ProviderEntry[] = [
    {
        name: 'perplexity',
        make: () => new PerplexityProvider({ apiKey: config.AI.PERPLEXITY_API_KEY, model: resolveModel('perplexity') }),
        defaultModel: 'sonar',
    },
    {
        name: 'openai',
        make: makeOpenAIProvider,
        defaultModel: 'gpt-4o',
    },
    {
        name: 'gemini',
        make: () => new GeminiProvider({ apiKey: config.AI.GEMINI_API_KEY, model: resolveModel('gemini') }),
        defaultModel: 'gemini-1.5-flash',
    },
];

export class AIClient {
    public async generateAnalysis(prompt: string): Promise<string | null> {
        const ordered = this.buildOrderedProviders();
        const chain = createFallbackChain(ordered.map(e => e.make()));

        if (!chain.isConfigured()) {
            logger.warn('[AI] No providers configured — skipping analysis');
            return null;
        }

        try {
            const result = await chain.chatCompletion({
                messages: [
                    { role: 'system', content: 'You are an expert crypto trading assistant. Strictly output JSON.' },
                    { role: 'user', content: prompt },
                ],
                temperature: 0.2,
            });
            logger.info('[AI] Analysis generated successfully');
            return result.content;
        } catch (error: any) {
            logger.error(`[AI] All providers failed: ${error.message}`);
            return null;
        }
    }

    public async getProviderHealth(probe: boolean = false): Promise<AIProviderHealth[]> {
        const fallbackList = config.AI.FALLBACK_LIST;
        const results: AIProviderHealth[] = [];

        for (const entry of PROVIDER_REGISTRY) {
            const provider = entry.make();
            const configured = provider.isConfigured();
            const fallbackIndex = fallbackList.indexOf(entry.name);
            const inFallbackList = fallbackIndex >= 0;
            const model = resolveModel(entry.name);

            if (!configured) {
                results.push({ provider: entry.name, configured: false, model, inFallbackList, fallbackIndex: inFallbackList ? fallbackIndex : null, status: 'missing_key', message: 'API key missing' });
                continue;
            }

            if (!probe) {
                results.push({ provider: entry.name, configured: true, model, inFallbackList, fallbackIndex: inFallbackList ? fallbackIndex : null, status: 'configured', message: 'Configured (probe skipped)' });
                continue;
            }

            try {
                await provider.chatCompletion({
                    messages: [{ role: 'user', content: 'Return JSON: {"action":"HOLD","confidence":0,"reasoning":"probe"}' }],
                    temperature: 0,
                });
                results.push({ provider: entry.name, configured: true, model, inFallbackList, fallbackIndex: inFallbackList ? fallbackIndex : null, status: 'ok', message: 'Provider probe succeeded' });
            } catch (error: any) {
                results.push({ provider: entry.name, configured: true, model, inFallbackList, fallbackIndex: inFallbackList ? fallbackIndex : null, status: 'error', message: error?.message || 'Provider probe failed' });
            }
        }

        return results;
    }

    private buildOrderedProviders(): ProviderEntry[] {
        const fallbackList = config.AI.FALLBACK_LIST;
        return fallbackList
            .map(name => PROVIDER_REGISTRY.find(e => e.name === name))
            .filter((e): e is ProviderEntry => e !== undefined);
    }
}
