<?php

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

final class AISBW_Topic_Repository
{
    private wpdb $wpdb;
    private string $table;

    public function __construct()
    {
        global $wpdb;

        $this->wpdb = $wpdb;
        $this->table = $wpdb->prefix . 'aisbw_topics';
    }

    public function all(array $args = []): array
    {
        $limit = isset($args['limit']) ? max(1, min(200, absint($args['limit']))) : 50;
        $offset = isset($args['offset']) ? max(0, absint($args['offset'])) : 0;
        $status = isset($args['status']) ? sanitize_key((string) $args['status']) : '';

        if ($status) {
            return $this->wpdb->get_results(
                $this->wpdb->prepare(
                    "SELECT * FROM {$this->table} WHERE status = %s ORDER BY priority DESC, created_at DESC LIMIT %d OFFSET %d",
                    $status,
                    $limit,
                    $offset
                ),
                ARRAY_A
            ) ?: [];
        }

        return $this->wpdb->get_results(
            $this->wpdb->prepare(
                "SELECT * FROM {$this->table} ORDER BY created_at DESC LIMIT %d OFFSET %d",
                $limit,
                $offset
            ),
            ARRAY_A
        ) ?: [];
    }

    public function list_generated(array $args = []): array
    {
        $limit = isset($args['limit']) ? max(1, min(200, absint($args['limit']))) : 50;

        return $this->wpdb->get_results(
            $this->wpdb->prepare(
                "SELECT * FROM {$this->table}
                WHERE generated_content IS NOT NULL OR wp_post_id IS NOT NULL
                ORDER BY updated_at DESC
                LIMIT %d",
                $limit
            ),
            ARRAY_A
        ) ?: [];
    }

    public function get(int $id): ?array
    {
        $topic = $this->wpdb->get_row(
            $this->wpdb->prepare("SELECT * FROM {$this->table} WHERE id = %d", $id),
            ARRAY_A
        );

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

    public function create(array $data): int
    {
        $prepared = $this->prepare_data($data);
        $prepared['created_at'] = $this->now();
        $prepared['updated_at'] = $this->now();

        $inserted = $this->wpdb->insert($this->table, $prepared);

        if (false === $inserted) {
            throw new RuntimeException('Nie udało się zapisać tematu.');
        }

        return (int) $this->wpdb->insert_id;
    }

    public function update(int $id, array $data): void
    {
        $prepared = $this->prepare_data($data, $this->get($id) ?: []);
        $prepared['updated_at'] = $this->now();

        $updated = $this->wpdb->update($this->table, $prepared, ['id' => $id]);

        if (false === $updated) {
            throw new RuntimeException('Nie udało się zaktualizować tematu.');
        }
    }

    public function delete(int $id): void
    {
        $this->wpdb->delete($this->table, ['id' => $id], ['%d']);
    }

    public function update_status(int $id, string $status, ?string $last_error = null): void
    {
        $data = [
            'status' => $this->sanitize_status($status),
            'updated_at' => $this->now(),
        ];

        if (null !== $last_error) {
            $data['last_error'] = sanitize_textarea_field($last_error);
        }

        $this->wpdb->update($this->table, $data, ['id' => $id]);
    }

    public function save_brief(int $id, array $brief): void
    {
        $this->wpdb->update(
            $this->table,
            [
                'brief' => wp_json_encode($brief, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                'working_title' => sanitize_text_field($brief['working_title'] ?? ''),
                'status' => 'brief_ready',
                'last_error' => null,
                'updated_at' => $this->now(),
            ],
            ['id' => $id]
        );
    }

    public function save_generated_article(int $id, array $article): void
    {
        $this->wpdb->update(
            $this->table,
            [
                'generated_content' => wp_json_encode($article, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                'working_title' => sanitize_text_field($article['title'] ?? ''),
                'seo_title' => sanitize_text_field($article['meta_title'] ?? ''),
                'seo_description' => sanitize_textarea_field($article['meta_description'] ?? ''),
                'slug' => sanitize_title($article['slug'] ?? ''),
                'excerpt' => sanitize_textarea_field($article['excerpt'] ?? ''),
                'tags' => $this->tags_to_string($article['tags'] ?? []),
                'status' => 'draft_ready',
                'last_error' => null,
                'updated_at' => $this->now(),
            ],
            ['id' => $id]
        );
    }

    public function save_quality_result(int $id, array $result, string $status): void
    {
        $this->wpdb->update(
            $this->table,
            [
                'quality_score' => isset($result['quality_score']) ? absint($result['quality_score']) : null,
                'quality_result' => wp_json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                'risk_level' => $this->sanitize_risk_level((string) ($result['risk_level'] ?? 'normal')),
                'status' => $this->sanitize_status($status),
                'last_error' => null,
                'updated_at' => $this->now(),
            ],
            ['id' => $id]
        );
    }

    public function attach_wp_post(int $id, int $post_id, string $status): void
    {
        $this->wpdb->update(
            $this->table,
            [
                'wp_post_id' => $post_id,
                'status' => $this->sanitize_status($status),
                'updated_at' => $this->now(),
            ],
            ['id' => $id],
            ['%d', '%s', '%s'],
            ['%d']
        );
    }

    public function find_next_approved(): ?array
    {
        $topic = $this->wpdb->get_row(
            "SELECT * FROM {$this->table} WHERE status = 'approved' ORDER BY priority DESC, created_at ASC LIMIT 1",
            ARRAY_A
        );

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

    public function duplicate_exists(array $data, ?int $ignore_id = null): bool
    {
        $topic = sanitize_text_field((string) ($data['topic'] ?? ''));
        $primary_keyword = sanitize_text_field((string) ($data['primary_keyword'] ?? ''));
        $slug = sanitize_title((string) ($data['slug'] ?? $data['working_title'] ?? $topic));

        $where = [];
        $params = [];

        if ('' !== $topic) {
            $where[] = 'topic = %s';
            $params[] = $topic;
        }

        if ('' !== $primary_keyword) {
            $where[] = 'primary_keyword = %s';
            $params[] = $primary_keyword;
        }

        if ('' !== $slug) {
            $where[] = 'slug = %s';
            $params[] = $slug;
        }

        if (!$where) {
            return false;
        }

        $sql = "SELECT id FROM {$this->table} WHERE (" . implode(' OR ', $where) . ')';

        if ($ignore_id) {
            $sql .= ' AND id != %d';
            $params[] = $ignore_id;
        }

        $sql .= ' LIMIT 1';

        return null !== $this->wpdb->get_var($this->wpdb->prepare($sql, $params));
    }

    private function prepare_data(array $data, array $existing = []): array
    {
        return [
            'topic' => sanitize_text_field((string) ($data['topic'] ?? $existing['topic'] ?? '')),
            'working_title' => sanitize_text_field((string) ($data['working_title'] ?? $existing['working_title'] ?? '')),
            'primary_keyword' => sanitize_text_field((string) ($data['primary_keyword'] ?? $existing['primary_keyword'] ?? '')),
            'secondary_keywords' => sanitize_textarea_field((string) ($data['secondary_keywords'] ?? $existing['secondary_keywords'] ?? '')),
            'audience' => sanitize_text_field((string) ($data['audience'] ?? $existing['audience'] ?? '')),
            'search_intent' => sanitize_text_field((string) ($data['search_intent'] ?? $existing['search_intent'] ?? '')),
            'category_id' => isset($data['category_id']) ? absint($data['category_id']) : (int) ($existing['category_id'] ?? 0),
            'tags' => sanitize_textarea_field((string) ($data['tags'] ?? $existing['tags'] ?? '')),
            'priority' => max(0, min(100, absint($data['priority'] ?? $existing['priority'] ?? 50))),
            'risk_level' => $this->sanitize_risk_level((string) ($data['risk_level'] ?? $existing['risk_level'] ?? 'normal')),
            'publish_mode' => $this->sanitize_publish_mode((string) ($data['publish_mode'] ?? $existing['publish_mode'] ?? 'draft_only')),
            'language' => $this->sanitize_language((string) ($data['language'] ?? $existing['language'] ?? '')),
            'status' => $this->sanitize_status((string) ($data['status'] ?? $existing['status'] ?? 'idea')),
            'notes' => sanitize_textarea_field((string) ($data['notes'] ?? $existing['notes'] ?? '')),
            'brief' => array_key_exists('brief', $data) ? $data['brief'] : ($existing['brief'] ?? null),
        ];
    }

    private function sanitize_language(string $lang): string
    {
        $lang = sanitize_key($lang);
        $allowed = class_exists('AISBW_Multilingual_Premium')
            ? AISBW_Multilingual_Premium::get_allowed_languages()
            : ['pl'];
        $default = (string) get_option('aisbw_default_language', 'pl');

        if (!in_array($lang, $allowed, true)) {
            $lang = $default;
        }

        if (!aisbw_is_premium() && 'pl' !== $lang) {
            return 'pl';
        }

        return $lang;
    }

    private function sanitize_status(string $status): string
    {
        $allowed = [
            'idea',
            'approved',
            'brief_ready',
            'generating',
            'draft_ready',
            'wp_draft_created',
            'review_required',
            'scheduled',
            'published',
            'rejected',
            'failed',
        ];

        return in_array($status, $allowed, true) ? $status : 'idea';
    }

    private function sanitize_risk_level(string $risk_level): string
    {
        return in_array($risk_level, ['low', 'normal', 'high'], true) ? $risk_level : 'normal';
    }

    private function sanitize_publish_mode(string $publish_mode): string
    {
        return in_array($publish_mode, ['draft_only', 'autopublish'], true) ? $publish_mode : 'draft_only';
    }

    private function tags_to_string(mixed $tags): string
    {
        if (is_array($tags)) {
            return implode(', ', array_filter(array_map('sanitize_text_field', $tags)));
        }

        return sanitize_textarea_field((string) $tags);
    }

    private function now(): string
    {
        return current_time('mysql');
    }
}
