<?php

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

final class AISBW_AI_Client
{
    private AISBW_Run_Repository $runs;
    private AISBW_Logger $logger;

    public function __construct(?AISBW_Run_Repository $runs = null, ?AISBW_Logger $logger = null)
    {
        $this->runs = $runs ?: new AISBW_Run_Repository();
        $this->logger = $logger ?: new AISBW_Logger();
    }

    public function request_json(
        array $messages,
        array $schema,
        string $schema_name,
        ?string $model = null,
        ?int $topic_id = null,
        string $run_type = 'openai_request'
    ): array {
        if (AISBW_Settings::get_bool('aisbw_test_mode_enabled')) {
            return $this->request_mock_json($messages, $schema_name, $topic_id, $run_type);
        }

        $max_requests = absint(AISBW_Settings::get('aisbw_max_ai_requests_per_day', 20));

        if ($max_requests > 0 && $this->runs->count_today() >= $max_requests) {
            throw new RuntimeException(__('AI daily request limit exceeded.', 'guco-ai-blog-writer'));
        }

        $run_id = $this->runs->start($topic_id, $run_type, [
            'provider' => 'wp_ai_client',
            'model' => 'wordpress_core',
            'messages' => $messages,
            'schema_name' => $schema_name,
        ]);

        $this->logger->info($run_type . '_started', 'Rozpoczęto wywołanie AI przez WordPress AI Client.', [
            'provider' => 'wp_ai_client',
        ], $topic_id);

        try {
            if (function_exists('set_time_limit')) {
                @set_time_limit(300);
            }
            $system_prompt = '';
            $user_prompt = '';
            foreach ($messages as $msg) {
                if (isset($msg['role']) && 'system' === $msg['role']) {
                    $system_prompt = $msg['content'];
                } elseif (isset($msg['role']) && 'user' === $msg['role']) {
                    $user_prompt = $msg['content'];
                }
            }

            if (empty($user_prompt)) {
                $user_prompt = wp_json_encode($messages);
            }

            if (!function_exists('wp_ai_client_prompt')) {
                throw new RuntimeException(__('WordPress AI Client is not available on this site. Please upgrade to WordPress 7.0+ or configure an AI Connector.', 'guco-ai-blog-writer'));
            }

            $builder = wp_ai_client_prompt($user_prompt);
            if (!empty($system_prompt)) {
                $builder->using_system_instruction($system_prompt);
            }
            $builder->as_json_response($schema);

            $result = $builder->generate_text();

            if (is_wp_error($result)) {
                throw new RuntimeException($result->get_error_message());
            }

            $decoded = json_decode($result, true);
            if (!is_array($decoded)) {
                throw new RuntimeException(__('AI Client returned invalid JSON.', 'guco-ai-blog-writer'));
            }

            $output = $this->extract_structured_output($decoded, $schema);
            $this->runs->finish($run_id, $output, []);
            $this->logger->info($run_type . '_finished', 'Zakończono wywołanie AI.', [
                'provider' => 'wp_ai_client',
            ], $topic_id);

            return $output;
        } catch (Throwable $e) {
            $message = $e->getMessage();
            $this->runs->fail($run_id, $message);
            $this->logger->error($run_type . '_failed', $message, [
                'provider' => 'wp_ai_client',
            ], $topic_id);
            throw $e;
        }
    }

    private function request_mock_json(array $messages, string $schema_name, ?int $topic_id, string $run_type): array
    {
        $input = $this->extract_mock_input($messages);
        $run_id = $this->runs->start($topic_id, $run_type, [
            'model' => 'aisbw-test-mode',
            'messages' => $messages,
            'schema_name' => $schema_name,
            'test_mode' => true,
        ]);

        $this->logger->info($run_type . '_started', 'Tryb testowy: pominięto wywołanie zewnętrznego API AI.', ['schema_name' => $schema_name], $topic_id);
        $output = $this->mock_output($schema_name, $run_type, $input);
        $this->runs->finish($run_id, $output, ['input' => 0, 'output' => 0]);
        $this->logger->info($run_type . '_finished', 'Tryb testowy: zwrócono przykładową odpowiedź.', [], $topic_id);

        return $output;
    }

    private function extract_mock_input(array $messages): array
    {
        foreach (array_reverse($messages) as $message) {
            if (!is_array($message) || ($message['role'] ?? '') !== 'user') {
                continue;
            }

            $content = $message['content'] ?? '';

            if (!is_string($content)) {
                continue;
            }

            $decoded = json_decode($content, true);

            if (is_array($decoded)) {
                return $decoded;
            }
        }

        return [];
    }

    private function mock_output(string $schema_name, string $run_type, array $input): array
    {
        if ('aisbw_brief' === $schema_name || 'brief_generation' === $run_type) {
            return $this->mock_brief($input);
        }

        if ('aisbw_article' === $schema_name || 'article_generation' === $run_type) {
            return $this->mock_article($input);
        }

        if ('aisbw_quality_check' === $schema_name || 'quality_check' === $run_type) {
            return $this->mock_quality_check($input);
        }

        if ('aisbw_title_suggestions' === $schema_name || 'title_suggestions' === $run_type) {
            return $this->mock_title_suggestions($input);
        }

        return [];
    }

    private function mock_brief(array $input): array
    {
        $topic = sanitize_text_field((string) ($input['topic'] ?? 'Przykładowy temat blogowy'));
        $primary_keyword = sanitize_text_field((string) ($input['primary_keyword'] ?? $topic));
        $audience = sanitize_text_field((string) ($input['audience'] ?? 'czytelnik bloga'));
        $intent = sanitize_text_field((string) ($input['search_intent'] ?? 'informational'));

        return [
            'working_title' => $topic,
            'angle' => 'Praktyczny poradnik pokazujący najważniejsze decyzje, typowe błędy i prostą ścieżkę wyboru.',
            'target_reader' => $audience ?: 'czytelnik szukający praktycznej odpowiedzi',
            'search_intent' => $intent ?: 'informational',
            'outline' => [
                [
                    'heading' => 'Dlaczego warto dobrze zrozumieć temat: ' . $primary_keyword,
                    'points' => [
                        'krótkie wyjaśnienie problemu',
                        'najczęstsze potrzeby czytelnika',
                        'co będzie można zdecydować po lekturze',
                    ],
                ],
                [
                    'heading' => 'Na co zwrócić uwagę przed podjęciem decyzji',
                    'points' => [
                        'najważniejsze kryteria wyboru',
                        'praktyczne przykłady zastosowania',
                        'typowe błędy do uniknięcia',
                    ],
                ],
                [
                    'heading' => 'Podsumowanie i następne kroki',
                    'points' => [
                        'krótka checklista',
                        'rekomendacja zależna od potrzeb',
                    ],
                ],
            ],
            'must_cover' => [
                'definicja problemu',
                'praktyczne kryteria wyboru',
                'krótkie podsumowanie',
            ],
            'avoid' => [
                'niepotwierdzone statystyki',
                'konkretne ceny bez źródeł',
                'nachalny język sprzedażowy',
            ],
            'faq_questions' => [
                'Od czego zacząć?',
                'Jak uniknąć najczęstszych błędów?',
                'Kiedy warto poprosić o dodatkową pomoc?',
            ],
            'requires_fresh_research' => false,
        ];
    }

    private function mock_article(array $input): array
    {
        $topic = sanitize_text_field((string) ($input['topic'] ?? 'Przykładowy temat blogowy'));
        $primary_keyword = sanitize_text_field((string) ($input['primary_keyword'] ?? $topic));
        $slug = sanitize_title($topic);

        if ('' === $slug) {
            $slug = 'przykladowy-wpis-testowy';
        }

        return [
            'title' => $topic . ' - praktyczny poradnik',
            'slug' => $slug,
            'excerpt' => 'Krótki poradnik testowy pokazujący, jak podejść do tematu krok po kroku.',
            'meta_title' => $topic . ' - poradnik',
            'meta_description' => 'Sprawdź praktyczny poradnik testowy i zobacz, na co zwrócić uwagę przed podjęciem decyzji.',
            'content_html' => '<h2>Od czego zacząć?</h2><p>To jest przykładowa treść wygenerowana w trybie testowym Gu&Co AI Blog Writer. Pozwala sprawdzić cały workflow bez używania zewnętrznego API AI.</p><h2>Najważniejsze kryteria</h2><p>Przy temacie takim jak ' . esc_html($topic) . ' warto zacząć od określenia potrzeb, ograniczeń i oczekiwanego efektu.</p><ul><li>Ustal cel i odbiorcę.</li><li>Porównaj dostępne warianty.</li><li>Unikaj decyzji opartych na pojedynczym argumencie.</li></ul><h2>Podsumowanie</h2><p>Tryb testowy służy do walidacji panelu, zapisu danych, quality checka i tworzenia szkicu WordPress bez kosztów API.</p>',
            'tags' => array_values(array_filter(array_unique([
                $primary_keyword,
                'poradnik',
                'test-guco-ai-blog-writer',
            ]))),
            'faq' => [
                [
                    'question' => 'Czy to jest prawdziwa odpowiedź zewnętrznego modelu AI?',
                    'answer' => 'Nie. To przykładowa odpowiedź lokalna używana wyłącznie do testów workflow.',
                ],
                [
                    'question' => 'Czy można z niej utworzyć szkic WordPress?',
                    'answer' => 'Tak. Szkic pozwala sprawdzić mapowanie tytułu, slug, treści, excerptu, tagów i metadanych.',
                ],
            ],
        ];
    }

    private function mock_quality_check(array $input): array
    {
        $article = isset($input['article']) && is_array($input['article']) ? $input['article'] : [];
        $content = (string) ($article['content_html'] ?? '');
        $passed = '' !== trim($content);

        return [
            'passed' => $passed,
            'quality_score' => $passed ? 88 : 0,
            'risk_level' => 'low',
            'issues' => $passed ? [
                [
                    'type' => 'test_mode',
                    'severity' => 'minor',
                    'message' => 'Wynik pochodzi z trybu testowego, nie z rzeczywistej oceny AI.',
                ],
            ] : [
                [
                    'type' => 'content',
                    'severity' => 'critical',
                    'message' => 'Brak treści HTML do oceny.',
                ],
            ],
            'requires_human_review' => false,
            'recommended_action' => $passed ? 'create_wp_draft' : 'reject',
        ];
    }

    private function mock_title_suggestions(array $input): array
    {
        $posts = isset($input['published_posts']) && is_array($input['published_posts']) ? $input['published_posts'] : [];
        $first_post = isset($posts[0]) && is_array($posts[0]) ? $posts[0] : [];
        $seed_title = sanitize_text_field((string) ($first_post['title'] ?? 'popularny temat na blogu'));
        $seed_title = $this->truncate_label($seed_title, 70);
        $categories = isset($first_post['categories']) && is_array($first_post['categories']) ? $first_post['categories'] : [];
        $tags = isset($first_post['tags']) && is_array($first_post['tags']) ? $first_post['tags'] : [];
        $seed_keyword = sanitize_text_field((string) ($tags[0] ?? $categories[0] ?? 'blog'));

        if ('' === $seed_keyword) {
            $seed_keyword = 'blog';
        }

        return [
            'suggestions' => [
                [
                    'title' => 'Jak rozwinąć temat: ' . $seed_title,
                    'primary_keyword' => $seed_keyword,
                    'secondary_keywords' => [$seed_keyword . ' poradnik', 'kolejne kroki', 'praktyczne wskazówki'],
                    'audience' => 'czytelnicy zainteresowani podobnymi poradnikami',
                    'search_intent' => 'informational',
                    'angle' => 'Kontynuacja najnowszego opublikowanego wpisu w formie praktycznego poradnika.',
                    'rationale' => 'Tryb testowy proponuje temat bazujący na najnowszym wpisie, żeby sprawdzić workflow bez API.',
                    'risk_level' => 'normal',
                ],
                [
                    'title' => 'Najczęstsze błędy przy temacie: ' . $seed_keyword,
                    'primary_keyword' => $seed_keyword . ' błędy',
                    'secondary_keywords' => [$seed_keyword, 'błędy', 'checklista'],
                    'audience' => 'czytelnicy szukający szybkiej checklisty',
                    'search_intent' => 'informational',
                    'angle' => 'Lista błędów i sposobów ich uniknięcia.',
                    'rationale' => 'Ten format naturalnie uzupełnia poradniki i dobrze działa jako wpis wspierający klaster.',
                    'risk_level' => 'normal',
                ],
                [
                    'title' => 'Od czego zacząć, gdy interesuje Cię ' . $seed_keyword,
                    'primary_keyword' => $seed_keyword . ' od czego zacząć',
                    'secondary_keywords' => [$seed_keyword, 'dla początkujących', 'pierwsze kroki'],
                    'audience' => 'początkujący czytelnicy bloga',
                    'search_intent' => 'informational',
                    'angle' => 'Wprowadzenie dla osób, które trafiły na blog po raz pierwszy.',
                    'rationale' => 'Propozycja tworzy wejściowy artykuł dla tego samego obszaru tematycznego.',
                    'risk_level' => 'low',
                ],
            ],
        ];
    }

    private function truncate_label(string $value, int $length): string
    {
        if (function_exists('mb_strlen') && function_exists('mb_substr')) {
            return mb_strlen($value, 'UTF-8') > $length ? mb_substr($value, 0, $length, 'UTF-8') . '...' : $value;
        }

        return $this->truncate($value, $length);
    }

    private function extract_structured_output(array $decoded, array $schema = []): array
    {
        $candidates = [];

        if ($this->matches_schema_required_fields($decoded, $schema)) {
            return $decoded;
        }

        if (isset($decoded['output_text']) && is_string($decoded['output_text'])) {
            $candidates[] = $decoded['output_text'];
        }

        if (isset($decoded['response']) && is_string($decoded['response'])) {
            $candidates[] = $decoded['response'];
        }

        if (isset($decoded['output']) && is_array($decoded['output'])) {
            foreach ($decoded['output'] as $output_item) {
                if (!is_array($output_item) || empty($output_item['content']) || !is_array($output_item['content'])) {
                    continue;
                }

                foreach ($output_item['content'] as $content_item) {
                    if (!is_array($content_item)) {
                        continue;
                    }

                    if (isset($content_item['json']) && is_array($content_item['json'])) {
                        return $content_item['json'];
                    }

                    if (isset($content_item['text']) && is_string($content_item['text'])) {
                        $candidates[] = $content_item['text'];
                    }

                    if (isset($content_item['text']['value']) && is_string($content_item['text']['value'])) {
                        $candidates[] = $content_item['text']['value'];
                    }
                }
            }
        }

        if (isset($decoded['content']) && is_array($decoded['content'])) {
            foreach ($decoded['content'] as $content_item) {
                if (!is_array($content_item)) {
                    continue;
                }

                if ('tool_use' === ($content_item['type'] ?? '') && isset($content_item['input']) && is_array($content_item['input'])) {
                    return $content_item['input'];
                }

                if (isset($content_item['text']) && is_string($content_item['text'])) {
                    $candidates[] = $content_item['text'];
                }
            }
        }

        if (isset($decoded['candidates']) && is_array($decoded['candidates'])) {
            foreach ($decoded['candidates'] as $candidate) {
                if (!is_array($candidate) || empty($candidate['content']['parts']) || !is_array($candidate['content']['parts'])) {
                    continue;
                }

                foreach ($candidate['content']['parts'] as $part) {
                    if (isset($part['text']) && is_string($part['text'])) {
                        $candidates[] = $part['text'];
                    }
                }
            }
        }

        if (isset($decoded['choices'][0]['message']['content']) && is_string($decoded['choices'][0]['message']['content'])) {
            $candidates[] = $decoded['choices'][0]['message']['content'];
        }

        foreach ($candidates as $candidate) {
            $parsed = $this->decode_json_candidate($candidate);

            if (is_array($parsed)) {
                return $parsed;
            }
        }

        throw new RuntimeException('Nie znaleziono structured output w odpowiedzi AI.');
    }

    private function matches_schema_required_fields(array $decoded, array $schema): bool
    {
        $required = $schema['required'] ?? [];

        if (!is_array($required) || !$required) {
            return false;
        }

        foreach ($required as $key) {
            if (!is_string($key) || !array_key_exists($key, $decoded)) {
                return false;
            }
        }

        return true;
    }

    private function decode_json_candidate(string $candidate): ?array
    {
        $candidate = trim($candidate);
        $candidate = preg_replace('/^```(?:json)?\s*/', '', $candidate) ?? $candidate;
        $candidate = preg_replace('/\s*```$/', '', $candidate) ?? $candidate;

        $decoded = json_decode($candidate, true);

        return is_array($decoded) ? $decoded : null;
    }

    private function truncate(string $value, int $length = 2000): string
    {
        if (strlen($value) <= $length) {
            return $value;
        }

        return substr($value, 0, $length) . '...';
    }
}
