<?php
namespace CAE\Modules\ContentEngine;

use CAE\Lib\Database;

class ContentExtras
{
    private Database     $db;
    private OpenAIClient $openai;

    public function __construct()
    {
        $this->db     = Database::getInstance();
        $this->openai = new OpenAIClient();
    }

    // ── Meta Tags ────────────────────────────────────────────────

    public function generateMetaTags(int $contentId): array
    {
        $item = $this->getContent($contentId);
        $excerpt = mb_substr(strip_tags($item['output'] ?? ''), 0, 500);

        $sys = 'You are an SEO expert. Generate meta tags. Return ONLY valid JSON with exactly these keys: '
             . 'title_tag (max 60 chars, includes primary keyword), meta_description (max 160 chars, compelling), '
             . 'og_title (max 70 chars), og_description (max 200 chars), focus_keyword (single phrase), '
             . 'secondary_keywords (array of 4 related phrases).';

        $usr = "Article title: {$item['title']}\n"
             . "Primary keyword: {$item['primary_keyword']}\n"
             . "Business: {$item['business_name']}\n"
             . "Content excerpt: {$excerpt}";

        $response = $this->openai->chat($sys, $usr);
        $result   = $this->parseJson($response['content']);
        $this->saveExtra($contentId, 'meta_tags', $result);
        return $result;
    }

    // ── Schema Markup ────────────────────────────────────────────

    public function generateSchema(int $contentId): string
    {
        $item     = $this->getContent($contentId);
        $pageType = strtolower($item['page_type_name'] ?? '');
        $type     = str_contains($pageType, 'blog') ? 'BlogPosting'
                  : (str_contains($pageType, 'faq') ? 'FAQPage' : 'Article');
        $excerpt  = mb_substr(strip_tags($item['output'] ?? ''), 0, 300);

        $sys = 'You are an SEO schema expert. Generate a complete, valid JSON-LD schema object. '
             . 'Return ONLY the raw JSON starting with {"@context":... — no markdown, no code blocks.';

        $usr = "Type: {$type}\n"
             . "Title: {$item['title']}\n"
             . "Organization: {$item['business_name']}\n"
             . "Website: {$item['website_url']}\n"
             . "Primary keyword: {$item['primary_keyword']}\n"
             . "Excerpt: {$excerpt}";

        $response = $this->openai->chat($sys, $usr);
        $schema   = trim(preg_replace('/```json?|```/', '', $response['content']));
        $this->saveExtra($contentId, 'schema_markup', $schema);
        return $schema;
    }

    // ── Anchor Text ──────────────────────────────────────────────

    public function generateAnchorText(int $contentId): array
    {
        $item = $this->getContent($contentId);

        $sys = 'You are an SEO link-building expert. Return ONLY valid JSON with key "anchors" containing an array. '
             . 'Each item: { "text": string, "type": "exact|partial|branded|generic", "use_case": string }.';

        $usr = "Generate 8 anchor text variations for:\n"
             . "Page: {$item['title']}\n"
             . "Primary keyword: {$item['primary_keyword']}\n"
             . "Brand: {$item['business_name']}";

        $response = $this->openai->chat($sys, $usr);
        $result   = $this->parseJson($response['content']);
        $this->saveExtra($contentId, 'anchor_text', $result);
        return $result;
    }

    // ── Image Suggestions ────────────────────────────────────────

    public function generateImageSuggestions(int $contentId): array
    {
        $item = $this->getContent($contentId);

        $sys = 'You are a content strategist. Return ONLY valid JSON with key "images" containing an array. '
             . 'Each item: { "position": "hero|section|inline", "alt_text": string, "description": string, "ai_prompt": string }.';

        $usr = "Suggest 5 images for:\n"
             . "Title: {$item['title']}\n"
             . "Keyword: {$item['primary_keyword']}\n"
             . "Business: {$item['business_name']}\n"
             . "Page type: {$item['page_type_name']}";

        $response = $this->openai->chat($sys, $usr);
        $result   = $this->parseJson($response['content']);
        $this->saveExtra($contentId, 'image_suggestions', $result);
        return $result;
    }

    // ── Internal Links ───────────────────────────────────────────

    public function getInternalLinks(int $contentId): array
    {
        $item = $this->getContent($contentId);

        return $this->db->fetchAll(
            "SELECT t.id AS topic_id, t.title, t.primary_keyword, t.status,
                    pt.name AS page_type,
                    gc.id AS content_id, gc.status AS content_status
             FROM topics t
             LEFT JOIN page_types pt        ON pt.id = t.page_type_id
             LEFT JOIN generated_content gc ON gc.topic_id = t.id
             WHERE t.project_id = ? AND t.id != ?
             ORDER BY gc.id DESC",
            [$item['project_id'], $item['topic_id']]
        );
    }

    // ── Topic Generation from Seed Keywords ──────────────────────

    public function generateTopicsFromSeed(
        int $projectId,
        int $pageTypeId,
        array $keywords,
        int $countPerKeyword = 5
    ): array {
        $project  = $this->db->fetch("SELECT * FROM projects WHERE id = ?", [$projectId]);
        $pageType = $this->db->fetch("SELECT * FROM page_types WHERE id = ?", [$pageTypeId]);

        if (!$project || !$pageType) {
            throw new \RuntimeException('Project or page type not found');
        }

        $keywordList = implode("\n", array_map(fn($k, $i) => ($i+1) . ". {$k}", $keywords, array_keys($keywords)));

        $sys = 'You are an expert SEO content strategist. Generate blog topic ideas. '
             . 'Return ONLY valid JSON with key "topics" containing an array of topic objects. '
             . 'Each topic must have: title (H1-ready, includes keyword), primary_keyword, '
             . 'supporting_keywords (comma-separated, 3-5 keywords), search_intent (informational|transactional|commercial|navigational), '
             . 'content_angle (what makes this article unique/valuable).';

        $usr = "Generate {$countPerKeyword} SEO blog topic ideas for EACH of these seed keywords:\n\n"
             . $keywordList . "\n\n"
             . "Business: {$project['business_name']}\n"
             . "Target audience: {$project['target_audience']}\n"
             . "Page type: {$pageType['name']}\n"
             . "Brand positioning: {$project['brand_positioning']}\n\n"
             . "Total topics needed: " . (count($keywords) * $countPerKeyword) . "\n"
             . "Each topic should target a different search intent or content angle. "
             . "Make titles compelling and SEO-ready.";

        $response = $this->openai->chat($sys, $usr);
        $result   = $this->parseJson($response['content']);
        return $result['topics'] ?? $result;
    }

    // ── AI Fix ──────────────────────────────────────────────────

    public function aiFix(int $contentId, string $instruction): array
    {
        $item    = $this->getContent($contentId);
        $topic   = $this->db->fetch("SELECT * FROM topics WHERE id = ?", [$item['topic_id']]);
        $project = $this->db->fetch("SELECT * FROM projects WHERE id = ?", [$item['project_id']]);

        $sys = 'You are an expert content editor. Apply the user\'s instruction to improve the HTML content. '
             . 'Return ONLY the complete updated HTML — no preamble, no markdown, no code fences. '
             . 'Preserve all HTML structure (<h1>, <h2>, <p>, <ul>, <li>, <strong>, <em>).';

        $usr = "INSTRUCTION: {$instruction}\n\n"
             . "CURRENT HTML CONTENT:\n{$item['output']}";

        $response   = $this->openai->chat($sys, $usr);
        $newContent = $response['content'];

        $qaResult  = (new \CAE\Modules\QAEngine\QAEngine())->check($newContent, $project, $topic);
        $newStatus = $qaResult['passed'] ? 'draft' : 'qa_failed';

        $this->db->update('generated_content', [
            'output'        => $newContent,
            'status'        => $newStatus,
            'input_tokens'  => (int)($item['input_tokens']  ?? 0) + $response['input_tokens'],
            'output_tokens' => (int)($item['output_tokens'] ?? 0) + $response['output_tokens'],
            'updated_at'    => date('Y-m-d H:i:s'),
        ], 'id = :id', ['id' => $contentId]);

        try {
            $this->db->insert('qa_logs', [
                'content_id'          => $contentId,
                'issues_found'        => json_encode($qaResult['issues']),
                'checks_detail'       => json_encode($qaResult['checks'] ?? []),
                'passed'              => $qaResult['passed'] ? 1 : 0,
                'word_count'          => $qaResult['word_count'],
                'keyword_density'     => $qaResult['keyword_density'],
                'readability_score'   => $qaResult['readability_score']   ?? 0,
                'avg_sentence_length' => $qaResult['avg_sentence_length'] ?? 0,
                'paragraph_count'     => $qaResult['paragraph_count']     ?? 0,
                'unique_word_ratio'   => $qaResult['unique_word_ratio']   ?? 0,
                'h1_count'            => $qaResult['h1_count'],
                'retry_count'         => 0,
                'created_at'          => date('Y-m-d H:i:s'),
            ]);
        } catch (\PDOException $ignored) {}

        return ['output' => $newContent, 'qa' => $qaResult, 'status' => $newStatus];
    }

    // ── Helpers ──────────────────────────────────────────────────

    private function getContent(int $contentId): array
    {
        $row = $this->db->fetch(
            "SELECT gc.*, t.title, t.primary_keyword, t.search_intent,
                    t.content_angle, t.project_id, t.id AS topic_id,
                    p.business_name, p.website_url,
                    pt.name AS page_type_name
             FROM generated_content gc
             JOIN topics t      ON t.id  = gc.topic_id
             JOIN projects p    ON p.id  = t.project_id
             JOIN page_types pt ON pt.id = t.page_type_id
             WHERE gc.id = ?",
            [$contentId]
        );
        if (!$row) throw new \RuntimeException("Content #{$contentId} not found");
        return $row;
    }

    private function parseJson(string $text): array
    {
        $text = preg_replace('/```json?\s*/i', '', $text);
        $text = preg_replace('/```/', '', $text);
        $text = trim($text);
        $data = json_decode($text, true);
        if (json_last_error() === JSON_ERROR_NONE) return $data;
        if (preg_match('/\{.*\}/s', $text, $m)) {
            $data = json_decode($m[0], true);
            if (json_last_error() === JSON_ERROR_NONE) return $data;
        }
        return ['raw' => $text, 'parse_error' => json_last_error_msg()];
    }

    private function saveExtra(int $contentId, string $key, mixed $value): void
    {
        $row     = $this->db->fetch("SELECT meta_extras FROM generated_content WHERE id = ?", [$contentId]);
        $extras  = !empty($row['meta_extras']) ? (json_decode($row['meta_extras'], true) ?? []) : [];
        $extras[$key] = $value;
        $this->db->update(
            'generated_content',
            ['meta_extras' => json_encode($extras), 'updated_at' => date('Y-m-d H:i:s')],
            'id = :id',
            ['id' => $contentId]
        );
    }
}
