<?php

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

final class AISBW_Content_Generator
{
    private AISBW_Topic_Repository $topics;
    private AISBW_AI_Client $client;
    private AISBW_Logger $logger;

    public function __construct(
        ?AISBW_Topic_Repository $topics = null,
        ?AISBW_AI_Client $client = null,
        ?AISBW_Logger $logger = null
    ) {
        $this->topics = $topics ?: new AISBW_Topic_Repository();
        $this->client = $client ?: new AISBW_AI_Client();
        $this->logger = $logger ?: new AISBW_Logger();
    }

    public function generate_brief(int $topic_id): array
    {
        $topic = $this->require_topic($topic_id);
        $lang_code = $topic['language'] ?? 'pl';
        $lang_name = $this->resolve_language_name($lang_code);
        $this->topics->update_status($topic_id, 'generating');
        $this->logger->info('brief_generation_started', 'Rozpoczęto generowanie briefu.', [], $topic_id);

        try {
            $brief = $this->client->request_json(
                $this->messages(self::brief_prompt($lang_name), $this->brief_input($topic)),
                self::brief_schema(),
                'aisbw_brief',
                null,
                $topic_id,
                'brief_generation'
            );

            $this->validate_required($brief, ['working_title', 'angle', 'target_reader', 'search_intent', 'outline']);
            $this->topics->save_brief($topic_id, $brief);
            $this->logger->info('brief_generation_finished', 'Brief został wygenerowany.', [], $topic_id);

            return $brief;
        } catch (Throwable $e) {
            $this->topics->update_status($topic_id, 'failed', $e->getMessage());
            $this->logger->error('brief_generation_failed', $e->getMessage(), [], $topic_id);
            throw $e;
        }
    }

    public function generate_article(int $topic_id): array
    {
        $max_articles = absint(AISBW_Settings::get('aisbw_max_articles_per_day', 3));

        if (!AISBW_Settings::get_bool('aisbw_test_mode_enabled') && $max_articles > 0 && (new AISBW_Run_Repository())->count_today('article_generation') >= $max_articles) {
            throw new RuntimeException(__('Daily article generation limit exceeded.', 'guco-ai-blog-writer'));
        }

        $topic = $this->require_topic($topic_id);
        $lang_code = $topic['language'] ?? 'pl';
        $lang_name = $this->resolve_language_name($lang_code);

        if (empty($topic['brief'])) {
            $this->generate_brief($topic_id);
            $topic = $this->require_topic($topic_id);
        }

        $brief = json_decode((string) $topic['brief'], true);

        if (!is_array($brief)) {
            throw new RuntimeException(__('Brief is invalid or empty.', 'guco-ai-blog-writer'));
        }

        $this->topics->update_status($topic_id, 'generating');
        $this->logger->info('article_generation_started', 'Rozpoczęto generowanie artykułu.', [], $topic_id);

        try {
            $article = $this->client->request_json(
                $this->messages(self::article_prompt($lang_name), $this->article_input($topic, $brief)),
                self::article_schema(),
                'aisbw_article',
                null,
                $topic_id,
                'article_generation'
            );

            $this->validate_required($article, ['title', 'slug', 'excerpt', 'meta_title', 'meta_description', 'content_html', 'tags']);

            if ('' === trim((string) $article['content_html'])) {
                throw new RuntimeException(__('Generated article does not contain content_html.', 'guco-ai-blog-writer'));
            }

            $this->topics->save_generated_article($topic_id, $article);
            $this->logger->info('article_generation_finished', 'Artykuł został wygenerowany.', [], $topic_id);

            return $article;
        } catch (Throwable $e) {
            $this->topics->update_status($topic_id, 'failed', $e->getMessage());
            $this->logger->error('article_generation_failed', $e->getMessage(), [], $topic_id);
            throw $e;
        }
    }

    private function require_topic(int $topic_id): array
    {
        $topic = $this->topics->get($topic_id);

        if (!$topic) {
            throw new RuntimeException(__('Topic not found.', 'guco-ai-blog-writer'));
        }

        return $topic;
    }

    private function brief_input(array $topic): array
    {
        return [
            'topic' => $topic['topic'] ?? '',
            'primary_keyword' => $topic['primary_keyword'] ?? '',
            'secondary_keywords' => $this->split_list((string) ($topic['secondary_keywords'] ?? '')),
            'audience' => $topic['audience'] ?? '',
            'search_intent' => $topic['search_intent'] ?? '',
            'brand_style' => (string) AISBW_Settings::get('aisbw_default_tone', __('practical, simple, specific', 'guco-ai-blog-writer')),
            'editorial_notes' => $topic['notes'] ?? '',
        ];
    }

    private function article_input(array $topic, array $brief): array
    {
        return [
            'topic' => $topic['topic'] ?? '',
            'brief' => $brief,
            'primary_keyword' => $topic['primary_keyword'] ?? '',
            'secondary_keywords' => $this->split_list((string) ($topic['secondary_keywords'] ?? '')),
            'brand_style' => (string) AISBW_Settings::get('aisbw_default_tone', __('practical, simple, specific', 'guco-ai-blog-writer')),
            'target_length' => (string) AISBW_Settings::get('aisbw_default_article_length', __('1200-1600 words', 'guco-ai-blog-writer')),
            'editorial_notes' => $topic['notes'] ?? '',
            'seo_rules' => [
                'Nie upychaj słów kluczowych.',
                'Nie dodawaj h1.',
                'Zwróć HTML z h2, h3, p, ul, ol.',
            ],
        ];
    }

    private function messages(string $system_prompt, array $input): array
    {
        return [
            [
                'role' => 'system',
                'content' => $system_prompt,
            ],
            [
                'role' => 'user',
                'content' => wp_json_encode($input, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            ],
        ];
    }

    private function split_list(string $value): array
    {
        if ('' === trim($value)) {
            return [];
        }

        return array_values(array_filter(array_map('trim', explode(',', $value))));
    }

    private function validate_required(array $data, array $keys): void
    {
        foreach ($keys as $key) {
            if (!array_key_exists($key, $data)) {
                throw new RuntimeException(sprintf(__('Missing field in AI response: %s', 'guco-ai-blog-writer'), $key));
            }
        }
    }

    private function resolve_language_name(string $code): string
    {
        if (class_exists('AISBW_Multilingual_Premium')) {
            return AISBW_Multilingual_Premium::resolve_language_name($code);
        }

        return 'polskim (Polish)';
    }

    private static function brief_prompt(string $lang_name): string
    {
        return sprintf(
            'Jesteś strategiem content SEO i redaktorem bloga. Przygotuj szczegółowy brief artykułu na podstawie danych wejściowych. Nie pisz całego artykułu. Przygotuj strukturę H2/H3, uwzględnij intencję wyszukiwania, wskaż czego unikać i pytania FAQ. Wszystkie teksty i pola w zwracanym JSON (takie jak working_title, outline, angle, avoid itp.) muszą być napisane w języku %s. Zwróć wyłącznie poprawny JSON zgodny ze schematem.',
            $lang_name
        );
    }

    private static function article_prompt(string $lang_name): string
    {
        return sprintf(
            'Jesteś doświadczonym autorem blogowym i redaktorem SEO. Napisz artykuł w języku %s na podstawie briefu. Pisz naturalnie, konkretnie i bez pustych fraz marketingowych. Nie zmyślaj faktów, cen, statystyk ani dat. Jeżeli brakuje danych, pisz neutralnie albo pomiń szczegół. Stosuj HTML: h2, h3, p, ul, ol. Nie dodawaj h1, CSS, JavaScript ani zewnętrznych obrazków. Zadbaj o SEO bez upychania słów kluczowych. Wszystkie pola zwracanego obiektu JSON (w tym title, slug, excerpt, meta_title, meta_description, content_html, tags oraz FAQ) muszą być napisane w języku %s. Zwróć wyłącznie JSON zgodny ze schematem.',
            $lang_name,
            $lang_name
        );
    }

    public static function brief_schema(): array
    {
        return [
            'type' => 'object',
            'additionalProperties' => false,
            'required' => ['working_title', 'angle', 'target_reader', 'search_intent', 'outline', 'must_cover', 'avoid', 'faq_questions', 'requires_fresh_research'],
            'properties' => [
                'working_title' => ['type' => 'string'],
                'angle' => ['type' => 'string'],
                'target_reader' => ['type' => 'string'],
                'search_intent' => ['type' => 'string'],
                'outline' => [
                    'type' => 'array',
                    'items' => [
                        'type' => 'object',
                        'additionalProperties' => false,
                        'required' => ['heading', 'points'],
                        'properties' => [
                            'heading' => ['type' => 'string'],
                            'points' => [
                                'type' => 'array',
                                'items' => ['type' => 'string'],
                            ],
                        ],
                    ],
                ],
                'must_cover' => ['type' => 'array', 'items' => ['type' => 'string']],
                'avoid' => ['type' => 'array', 'items' => ['type' => 'string']],
                'faq_questions' => ['type' => 'array', 'items' => ['type' => 'string']],
                'requires_fresh_research' => ['type' => 'boolean'],
            ],
        ];
    }

    public static function article_schema(): array
    {
        return [
            'type' => 'object',
            'additionalProperties' => false,
            'required' => ['title', 'slug', 'excerpt', 'meta_title', 'meta_description', 'content_html', 'tags', 'faq'],
            'properties' => [
                'title' => ['type' => 'string'],
                'slug' => ['type' => 'string'],
                'excerpt' => ['type' => 'string'],
                'meta_title' => ['type' => 'string'],
                'meta_description' => ['type' => 'string'],
                'content_html' => ['type' => 'string'],
                'tags' => ['type' => 'array', 'items' => ['type' => 'string']],
                'faq' => [
                    'type' => 'array',
                    'items' => [
                        'type' => 'object',
                        'additionalProperties' => false,
                        'required' => ['question', 'answer'],
                        'properties' => [
                            'question' => ['type' => 'string'],
                            'answer' => ['type' => 'string'],
                        ],
                    ],
                ],
            ],
        ];
    }
}
