<?php

namespace ZenoChatbot\Services\LLMService\AIClient\Providers\PromptBuilders;

use ZenoChatbot\Services\LLMService\AIClient\Config\AiConfig;
use ZenoChatbot\Services\LLMService\AIClient\Support\FileResource;

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Anthropic-specific prompt builder for the Messages API.
 */
class AnthropicPromptBuilder extends Builder
{
    /**
     * Models that do NOT support temperature/top_p/top_k parameters.
     * Opus 4.7+ returns 400 if these are included.
     */
    private const TEMPERATURE_UNSUPPORTED_PREFIXES = [
        'claude-opus-4-7',
        'claude-opus-4-8',
        'claude-opus-4-9',
        'claude-mythos',
    ];

    /**
     * Build final Anthropic Messages API payload.
     */
    public static function buildPayload(AiConfig $config, array $input): array
    {
        $systemText = static::buildSystemText($input);
        $messages = static::buildMessages($input);

        $payload = [
            'model' => $config->getModel(),
            'max_tokens' => max(1, (int)($input['max_tokens'] ?? $config->getMaxTokens())),
            'messages' => $messages,
        ];

        if ($systemText !== '') {
            $payload['system'] = $systemText;
        }

        if (static::supportsTemperature($config->getModel())) {
            $payload['temperature'] = (float)($input['temperature'] ?? $config->getTemperature());
        }

        return $payload;
    }

    /**
     * Build the system prompt as a single string for Anthropic's `system` field.
     */
    private static function buildSystemText(array $input): string
    {
        $sections = [];

        $systemPrompts = (array)($input['system_prompts'] ?? []);
        $joined = trim(implode("\n\n", array_filter($systemPrompts, fn($s) => is_string($s) && trim($s) !== '')));
        if ($joined !== '') {
            $sections[] = $joined;
        }

        $resources = (array)($input['resources'] ?? []);
        if (!empty($resources)) {
            $resText = static::buildResourceText($resources);
            if ($resText !== '') {
                $sections[] = $resText;
            }
        }

        return trim(implode("\n\n", $sections));
    }

    /**
     * Build the messages array from context history + current user message.
     * Supports multipart content with images and PDFs.
     */
    private static function buildMessages(array $input): array
    {
        $messages = [];

        $context = (array)($input['context'] ?? []);
        foreach ($context as $turn) {
            if (!is_array($turn)) {
                continue;
            }
            $msg = trim((string)($turn['message'] ?? ''));
            if ($msg === '') {
                continue;
            }
            $role = strtolower((string)($turn['role'] ?? 'user'));
            $role = in_array($role, ['assistant', 'model'], true) ? 'assistant' : 'user';
            $messages[] = ['role' => $role, 'content' => $msg];
        }

        $userText = (string)($input['message'] ?? '');
        $fileResources = $input['file_resources'] ?? [];

        if (!empty($fileResources)) {
            $content = static::buildMultipartContent($userText, $fileResources);
            $messages[] = ['role' => 'user', 'content' => $content];
        } elseif ($userText !== '') {
            $messages[] = ['role' => 'user', 'content' => $userText];
        }

        return $messages;
    }

    /**
     * Build multipart content array with text and file blocks for Anthropic.
     *
     * @param string $text The text prompt
     * @param FileResource[] $fileResources Array of file resources
     * @return array
     */
    private static function buildMultipartContent(string $text, array $fileResources): array
    {
        $content = [];

        foreach ($fileResources as $file) {
            if (!$file instanceof FileResource) {
                continue;
            }

            if ($file->isImage()) {
                $content[] = [
                    'type' => 'image',
                    'source' => [
                        'type' => 'base64',
                        'media_type' => $file->getMimeType(),
                        'data' => $file->getBase64Data(),
                    ],
                ];
            } elseif ($file->isPdf()) {
                $content[] = [
                    'type' => 'document',
                    'source' => [
                        'type' => 'base64',
                        'media_type' => $file->getMimeType(),
                        'data' => $file->getBase64Data(),
                    ],
                ];
            }
        }

        if ($text !== '') {
            $content[] = [
                'type' => 'text',
                'text' => $text,
            ];
        }

        return $content;
    }

    /**
     * Check if a model supports the temperature parameter.
     */
    private static function supportsTemperature(string $model): bool
    {
        foreach (static::TEMPERATURE_UNSUPPORTED_PREFIXES as $prefix) {
            if (str_starts_with($model, $prefix)) {
                return false;
            }
        }

        return true;
    }
}
