import { ChatMessage, FunctionCall, ProviderResponse } from '../../../types/chat';
import { GenericToolSchema, ParameterDefinition, StandardizedToolCall } from '../../../types/tool';

interface OpenRouterMessage {
    role: string;
    content: string;
    name?: string;
    tool_calls?: OpenRouterToolCall[];
}

interface OpenRouterToolCall {
    name: string;
    arguments?: Record<string, string>;
}

interface OpenRouterFunction {
    name: string;
    description: string;
    parameters: {
        type: string;
        properties: Record<string, ParameterDefinition>;
        required: string[];
    };
}

const MODELS_WITHOUT_SYSTEM_MESSAGES = ['davinci-codex'];

export function convertMessages(messages: ChatMessage[], model: string): OpenRouterMessage[] {
    const supportsSystemMessages = !MODELS_WITHOUT_SYSTEM_MESSAGES.includes(model);

    return messages.map((msg: any) => {
        let convertedMessage: Partial<OpenRouterMessage> = {
            content: msg.content,
        };

        switch (msg.role) {
            case 'system':
                convertedMessage.role = supportsSystemMessages ? 'system' : 'user';
                if (!supportsSystemMessages) {
                    convertedMessage.content = `System: ${msg.content}`;
                }
                break;
            case 'user':
            case 'assistant':
                convertedMessage.role = msg.role;
                break;
            case 'function':
                convertedMessage = {
                    role: 'function',
                    content: msg.content,
                    name: msg.name || 'unknown',
                };
                break;
            default:
                console.warn(`Unknown role "${msg.role}" encountered. Treating as "user".`);
                convertedMessage.role = 'user';
        }

        if (msg.role === 'assistant' && 'function_call' in msg && msg.function_call) {
            (convertedMessage as OpenRouterMessage).tool_calls = [convertToolCall({
                name: msg.function_call.name,
                arguments: msg.function_call.arguments,
            })];
        }

        return convertedMessage as OpenRouterMessage;
    });
}

export function convertFunctionCall(functionCall: FunctionCall): { name: string; arguments: string } {
    return {
        name: functionCall.name,
        arguments: JSON.stringify(functionCall.arguments)
    };
}

export function convertToolSchema(schema: GenericToolSchema): OpenRouterFunction {
    return {
        name: schema.name,
        description: schema.description,
        parameters: {
            type: 'object',
            properties: convertParameters(schema.parameters.properties),
            required: schema.parameters.required || [],
        },
    };
}

export function convertParameters(params: Record<string, ParameterDefinition>): Record<string, ParameterDefinition> {
    const result: Record<string, ParameterDefinition> = {};
    for (const [key, value] of Object.entries(params)) {
        result[key] = convertParameterDefinition(value);
    }
    return result;
}

export function convertParameterDefinition(param: ParameterDefinition): ParameterDefinition {
    const result: ParameterDefinition = { type: param.type };
    if (param.description) result.description = param.description;
    if (param.enum) result.enum = param.enum;
    if (param.items) result.items = convertParameterDefinition(param.items);
    if (param.properties) result.properties = convertParameters(param.properties);
    if (param.required) result.required = param.required;
    return result;
}

export function convertToolCall(call: OpenRouterToolCall): StandardizedToolCall {
    try {
        const convertedCall = {
            name: call.name,
            arguments: JSON.parse(call.arguments as any),
        };
        validateToolCall(convertedCall);
        return convertedCall;
    } catch (error) {
        throw new Error(`Failed to convert tool call: ${error instanceof Error ? error.message : String(error)}`);
    }
}

export function validateToolCall(toolCall: StandardizedToolCall): void {
    if (typeof toolCall.name !== 'string' || toolCall.name.trim() === '') {
        throw new Error('Invalid tool call: name must be a non-empty string');
    }
    if (typeof toolCall.arguments !== 'object' || toolCall.arguments === null) {
        throw new Error('Invalid tool call: arguments must be an object');
    }
}

export function convertToolCalls(toolCalls: OpenRouterToolCall[] | undefined): StandardizedToolCall[] {
    if (!toolCalls || toolCalls.length === 0) return [];
    return toolCalls.map(call => {
        try {
            return convertToolCall(call);
        } catch (error) {
            return null;
        }
    }).filter((call): call is StandardizedToolCall => call !== null);
}

export function convertUsage(usage: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number } | undefined): ProviderResponse['usage'] {
    return {
        promptTokens: usage?.prompt_tokens || 0,
        completionTokens: usage?.completion_tokens || 0,
        totalTokens: usage?.total_tokens || 0,
    };
}