<?php

if (! defined('ABSPATH')) {
    exit;
} final class PufferGo_Translation_Client
{
    public const ENDPOINT = '/api/wp/translate';

    public const TIMEOUT = 190;

    public const BATCH_SIZE = 30;

    public const MAX_BATCH_CHARS = 2000;

    public const DEFAULT_INSTRUCTIONS = '翻译时请使用行业惯用的规范术语，不要生硬直译专业术语；型号、编号等不应翻译的内容请保持原样；语气自然、专业，符合 B2B 制造业网站的调性。';

    public static function translate(array $items, string $target, string $source = ''): array
    {
        if (empty($items)) {
            return array('translations' => array(), 'creditsRemaining' => null, 'creditsConsumed' => null, 'sourceLanguage' => $source, );
        } $custom_prompt = self::build_custom_prompt();
        $chunks = self::build_chunks(array_values($items));
        $all_translations = array();
        $credits_remaining = null;
        $credits_consumed = 0;
        $resolved_source = $source;

        foreach ($chunks as $chunk_index => $chunk) {
            if (function_exists('puffergo_log')) {
                puffergo_log('Translate API chunk ' . ($chunk_index + 1) . '/' . count($chunks) . ' — ' . count($chunk) . ' items, target:' . $target);
            } $res = self::dispatch_chunk($chunk, $target, $source, $custom_prompt);

            foreach ($res['translations'] as $id => $text) {
                $all_translations[ $id ] = $text;
            }

if (null !== $res['creditsRemaining']) {
                $credits_remaining = $res['creditsRemaining'];
            }

if (null !== $res['creditsConsumed']) {
                $credits_consumed += $res['creditsConsumed'];
            }

if ('' === $resolved_source && '' !== $res['sourceLanguage']) {
                $resolved_source = $res['sourceLanguage'];
            }
        }

return array('translations' => $all_translations, 'creditsRemaining' => $credits_remaining, 'creditsConsumed' => $credits_consumed > 0 ? $credits_consumed : null, 'sourceLanguage' => $resolved_source, );
    }

    private static function build_chunks(array $items): array
    {
        $chunks = array();
        $current = array();
        $chars = 0;

        foreach ($items as $item) {
            $len = isset($item['text']) ? strlen((string) $item['text']) : 0;

            if (! empty($current) && (count($current) >= self::BATCH_SIZE || ($chars + $len) > self::MAX_BATCH_CHARS)) {
                $chunks[] = $current;
                $current = array();
                $chars = 0;
            } $current[] = $item;
            $chars += $len;
        }

if (! empty($current)) {
            $chunks[] = $current;
        }

return $chunks;
    }

    private static function dispatch_chunk(array $chunk, string $target, string $source, string $custom_prompt = ''): array
    {
        try {
            $res = self::send_chunk($chunk, $target, $source, $custom_prompt);
        } catch (PufferGo_API_Exception $e) {
            throw $e;
        } catch (Exception $e) {
            if (self::is_size_error($e)) {
                if (count($chunk) > 1) {
                    return self::bisect_chunk($chunk, $target, $source, $custom_prompt);
                }

if (function_exists('puffergo_log')) {
                    puffergo_log('Translate API: a single item exceeds the model budget — left untranslated.');
                }

return self::empty_result();
            }

throw $e;
        }

if (empty($res['translations']) && count($chunk) > 1) {
            return self::bisect_chunk($chunk, $target, $source, $custom_prompt);
        }

return $res;
    }

    private static function bisect_chunk(array $chunk, string $target, string $source, string $custom_prompt = ''): array
    {
        $mid = (int) floor(count($chunk) / 2);

        if (function_exists('puffergo_log')) {
            puffergo_log('Translate API: chunk too large (' . count($chunk) . ' items) — splitting and retrying.');
        } $left = self::dispatch_chunk(array_slice($chunk, 0, $mid), $target, $source, $custom_prompt);
        $right = self::dispatch_chunk(array_slice($chunk, $mid), $target, $source, $custom_prompt);

        return array('translations' => $left['translations'] + $right['translations'], 'creditsRemaining' => null !== $right['creditsRemaining'] ? $right['creditsRemaining'] : $left['creditsRemaining'], 'creditsConsumed' => self::sum_nullable($left['creditsConsumed'], $right['creditsConsumed']), 'sourceLanguage' => '' !== $left['sourceLanguage'] ? $left['sourceLanguage'] : $right['sourceLanguage'], );
    }

    private static function send_chunk(array $chunk, string $target, string $source, string $custom_prompt = ''): array
    {
        $payload = array('items' => array_values($chunk), 'targetLanguage' => $target, );

        if ('' !== $source) {
            $payload['sourceLanguage'] = $source;
        }

if ('' !== $custom_prompt) {
            $payload['customPrompt'] = $custom_prompt;
        } $raw = PufferGo_API_Client::get_instance()->post(self::ENDPOINT, $payload, array('timeout' => self::TIMEOUT, 'log_prefix' => 'Translate API', 'return_raw_result' => true, ));
        $data = isset($raw['data']) && is_array($raw['data']) ? $raw['data'] : array();
        $results = isset($data['results']) && is_array($data['results']) ? $data['results'] : array();
        $translations = array();

        foreach ($results as $row) {
            if (isset($row['id'])) {
                $translations[ (string) $row['id'] ] = isset($row['translation']) ? (string) $row['translation'] : '';
            }
        }

return array('translations' => $translations, 'creditsRemaining' => isset($raw['creditsRemaining']) ? (int) $raw['creditsRemaining'] : null, 'creditsConsumed' => isset($raw['creditsConsumed']) ? (int) $raw['creditsConsumed'] : null, 'sourceLanguage' => isset($data['sourceLanguage']) ? (string) $data['sourceLanguage'] : '', );
    }

    private static function is_size_error(Exception $e): bool
    {
        return (bool) preg_match('/max_tokens|finish_reason|truncat|too\s*long|context\s*length|exceed|length\s*limit/i', $e->getMessage());
    }

    private static function sum_nullable($a, $b)
    {
        if (null === $a && null === $b) {
            return null;
        }

return (int) $a + (int) $b;
    }

    private static function empty_result(): array
    {
        return array('translations' => array(), 'creditsRemaining' => null, 'creditsConsumed' => null, 'sourceLanguage' => '', );
    }

    private static function build_custom_prompt(): string
    {
        $lines = array();
        $context = get_option(PufferGo_Translation_REST::CONTEXT_OPTION, array());

        if (! is_array($context)) {
            $context = array();
        } $instructions = isset($context['instructions']) ? trim((string) $context['instructions']) : '';
        $lines[] = '' !== $instructions ? $instructions : self::DEFAULT_INSTRUCTIONS;
        $profile = get_option(PufferGo_Site_Profile::OPTION_KEY, array());

        if (! is_array($profile)) {
            $profile = array();
        } $industry = isset($profile['business']['industry']) ? trim((string) $profile['business']['industry']) : '';

        if ('' !== $industry) {
            $lines[] = "这是一家从事「{$industry}」行业的企业。";
        } $tone = isset($profile['advantage']['tone']) ? trim((string) $profile['advantage']['tone']) : '';

        if ('' !== $tone) {
            $lines[] = "翻译时请使用「{$tone}」的语气。";
        } $brand_name = isset($profile['identity']['brand_name']) ? trim((string) $profile['identity']['brand_name']) : '';

        if ('' !== $brand_name) {
            $lines[] = "品牌名「{$brand_name}」请勿翻译，保持原样。";
        }

return implode("\n", $lines);
    }
}
