<?php
namespace Analytics\Controllers\Api;

use Analytics\Lib\Database;
use Analytics\Lib\AiOverviewHelper;
use Analytics\Lib\Response;

class AiOverviewController
{
    private Database $db;

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

    // ── GET /api/projects/{projectId}/ai-overview/prompts ────────────────────
    public function listPrompts(int $projectId, array $query): void
    {
        $search    = $query['search']     ?? '';
        $dateRange = $query['date_range'] ?? '';
        $page      = max(1, (int)($query['page']  ?? 1));
        $limit     = max(1, (int)($query['limit'] ?? 10));
        $offset    = ($page - 1) * $limit;

        $sql    = 'SELECT * FROM brand_prompts WHERE brand_id = ?';
        $params = [$projectId];

        if ($search !== '') {
            $sql    .= ' AND prompt_text LIKE ?';
            $params[] = '%' . $search . '%';
        }
        if ($dateRange !== '') {
            $dates = explode(' to ', $dateRange);
            if (count($dates) === 2) {
                $sql    .= ' AND created_at BETWEEN ? AND ?';
                $params[] = $dates[0] . ' 00:00:00';
                $params[] = $dates[1] . ' 23:59:59';
            }
        }

        $countSql   = str_replace('SELECT *', 'SELECT COUNT(*)', $sql);
        $countRow   = $this->db->fetch($countSql, $params);
        $total      = (int)($countRow['COUNT(*)'] ?? 0);
        $totalPages = (int) ceil($total / $limit);

        $sql    .= " ORDER BY created_at DESC LIMIT {$limit} OFFSET {$offset}";
        $prompts = $this->db->fetchAll($sql, $params);

        $project    = $this->db->fetch('SELECT business_name, website_url FROM projects WHERE id = ?', [$projectId]);
        $nameVars   = $this->getNameVariations($projectId, $project['business_name'] ?? '');
        $domVars    = $this->getDomainVariations($projectId, $project['website_url'] ?? '');
        $competitors = $this->db->fetchAll('SELECT * FROM competitors WHERE brand_id = ?', [$projectId]);

        $results = [];
        foreach ($prompts as $p) {
            $pid = (int)$p['id'];

            $runs = $this->db->fetchAll(
                'SELECT ai_response FROM prompt_runs WHERE prompt_id = ?',
                [$pid]
            );
            $totalMentions = 0;
            foreach ($runs as $run) {
                $totalMentions += AiOverviewHelper::calcBrandMentions($run['ai_response'] ?? '', $nameVars);
            }

            $links = $this->db->fetchAll(
                'SELECT prl.url FROM prompt_run_links prl
                 JOIN prompt_runs pr ON prl.run_id = pr.id
                 WHERE pr.prompt_id = ?',
                [$pid]
            );
            $totalCitations = AiOverviewHelper::calcDomainCitations(
                array_map(fn($l) => ['url' => $l['url']], $links),
                $domVars
            );

            $compTotal = 0;
            foreach ($runs as $run) {
                $clean = strtolower($run['ai_response'] ?? '');
                foreach ($competitors as $c) {
                    if (!empty($c['competitor_name'])) {
                        $compTotal += substr_count($clean, strtolower($c['competitor_name']));
                    }
                }
            }
            foreach ($links as $link) {
                foreach ($competitors as $c) {
                    $cDomain = strtolower(preg_replace('#^https?://(www\.)?#', '', rtrim($c['competitor_url'] ?? '', '/')));
                    if (!empty($cDomain)) {
                        $urlCmp = strtolower(preg_replace('#^https?://(www\.)?#', '', $link['url']));
                        if (strpos($urlCmp, $cDomain) !== false) $compTotal++;
                    }
                }
            }

            $p['brand_mentions']       = $totalMentions;
            $p['domain_citations']     = $totalCitations;
            $p['competitors_mentions'] = $compTotal;
            $results[] = $p;
        }

        Response::json([
            'data'         => $results,
            'total'        => $total,
            'total_pages'  => $totalPages,
            'current_page' => $page,
        ]);
    }

    // ── POST /api/projects/{projectId}/ai-overview/prompts ───────────────────
    public function addPrompt(int $projectId, array $body): void
    {
        $text = trim($body['prompt_text'] ?? '');
        if ($text === '') {
            Response::error('Prompt text is required', 400);
            return;
        }

        $id = $this->db->insert('brand_prompts', [
            'brand_id'    => $projectId,
            'prompt_text' => $text,
            'created_at'  => date('Y-m-d H:i:s'),
        ]);

        Response::json(['success' => true, 'id' => $id]);
    }

    // ── DELETE /api/projects/{projectId}/ai-overview/prompts ─────────────────
    public function deletePrompts(int $projectId, array $body): void
    {
        $ids = $body['prompt_ids'] ?? [];
        if (!is_array($ids)) $ids = [$ids];
        $ids = array_filter(array_map('intval', $ids));

        if (empty($ids)) {
            Response::error('No prompt IDs provided', 400);
            return;
        }

        $placeholders = implode(',', array_fill(0, count($ids), '?'));
        $params       = array_merge($ids, [$projectId]);
        $this->db->query(
            "DELETE FROM brand_prompts WHERE id IN ({$placeholders}) AND brand_id = ?",
            $params
        );

        Response::json(['success' => true]);
    }

    // ── POST /api/ai-overview/prompts/{promptId}/run ──────────────────────────
    public function runPrompt(int $promptId, array $body): void
    {
        // Allow long-running AI calls; keep processing even if client disconnects
        set_time_limit(180);
        ignore_user_abort(true);

        $platformLabel      = $body['platform']             ?? 'ChatGPT';
        $modelVersion       = $body['model_version']        ?? '';
        $webSearchSupported = filter_var($body['web_search_supported'] ?? false, FILTER_VALIDATE_BOOLEAN);
        $countryCode        = $body['country_code']         ?? 'IN';

        if (!$modelVersion) {
            Response::error('model_version is required', 400);
            return;
        }

        $prompt = $this->db->fetch(
            'SELECT bp.*, p.business_name, p.website_url
             FROM brand_prompts bp
             JOIN projects p ON bp.brand_id = p.id
             WHERE bp.id = ?',
            [$promptId]
        );
        if (!$prompt) {
            Response::error('Prompt not found', 404);
            return;
        }

        $projectId  = (int)$prompt['brand_id'];
        $modelLabel = $platformLabel . ' (' . $modelVersion . ')';

        // ── Duplicate-run guard ───────────────────────────────────────────
        // If another request (same prompt + model) is already running and
        // started less than 3 minutes ago, reject instead of double-firing.
        $staleThreshold = date('Y-m-d H:i:s', strtotime('-3 minutes'));
        $inProgress = $this->db->fetch(
            "SELECT id FROM prompt_runs
             WHERE prompt_id = ? AND model = ? AND status = 'running'
               AND started_at > ?",
            [$promptId, $modelLabel, $staleThreshold]
        );
        if ($inProgress) {
            Response::json([
                'success'     => false,
                'in_progress' => true,
                'error'       => 'This model is already running for this prompt. Please wait.',
            ]);
            return;
        }

        // ── Pre-insert run record with status = running ───────────────────
        // Committed immediately (outside any transaction) so other connections
        // can see it and respect the duplicate guard above.
        $runId = $this->db->insert('prompt_runs', [
            'prompt_id'    => $promptId,
            'model'        => $modelLabel,
            'status'       => 'running',
            'started_at'   => date('Y-m-d H:i:s'),
            'created_at'   => date('Y-m-d H:i:s'),
        ]);

        // Store country preference (best-effort, non-critical)
        $this->db->query(
            'UPDATE brand_prompts SET country_code = ? WHERE id = ?',
            [$countryCode, $promptId]
        );

        $nameVars = $this->getNameVariations($projectId, $prompt['business_name']);
        $domVars  = $this->getDomainVariations($projectId, $prompt['website_url']);

        // ── Call DataforSEO ───────────────────────────────────────────────
        try {
            $result = AiOverviewHelper::runPrompt(
                $prompt['prompt_text'],
                $platformLabel,
                $modelVersion,
                $webSearchSupported,
                $countryCode
            );
        } catch (\Throwable $e) {
            $this->db->update('prompt_runs', ['status' => 'failed'], 'id = :id', ['id' => $runId]);
            Response::json(['success' => false, 'error' => $e->getMessage()]);
            return;
        }

        $aiText  = $result['ai_response'];
        $links   = $result['links'];

        $brandMentions   = AiOverviewHelper::calcBrandMentions($aiText, $nameVars);
        $domainCitations = AiOverviewHelper::calcDomainCitations($links, $domVars);
        $visScore        = AiOverviewHelper::calcVisibilityScore($brandMentions, $domainCitations, count($links));
        $intent          = AiOverviewHelper::calcIntentDistribution($prompt['prompt_text']);

        // ── Persist results in a single transaction ───────────────────────
        $this->db->pdo()->beginTransaction();
        try {
            // Update the pre-created run record with full response
            $this->db->update('prompt_runs', [
                'status'       => 'done',
                'model'        => $result['model_label'],
                'ai_response'  => $aiText,
                'snapshot_url' => $result['snapshot_url'],
            ], 'id = :id', ['id' => $runId]);

            foreach ($links as $link) {
                $this->db->insert('prompt_run_links', [
                    'run_id' => $runId,
                    'rank'   => $link['rank'],
                    'title'  => $link['title'],
                    'url'    => $link['url'],
                    'domain' => $link['domain'],
                ]);
            }

            $this->db->update('brand_prompts', [
                'brand_mentions'   => $brandMentions,
                'domain_citations' => $domainCitations,
                'total_citations'  => count($links),
                'visibility_score' => $visScore,
                'intent_info'      => $intent['info'],
                'intent_nav'       => $intent['nav'],
                'intent_comm'      => $intent['comm'],
                'intent_tran'      => $intent['tran'],
                'intent_task'      => $intent['task'],
            ], 'id = :id', ['id' => $promptId]);

            $this->db->pdo()->commit();
        } catch (\Throwable $e) {
            if ($this->db->pdo()->inTransaction()) $this->db->pdo()->rollBack();
            // Mark run failed so the guard doesn't block future attempts
            $this->db->update('prompt_runs', ['status' => 'failed'], 'id = :id', ['id' => $runId]);
            Response::json(['success' => false, 'error' => $e->getMessage()]);
            return;
        }

        $competitors    = $this->db->fetchAll('SELECT * FROM competitors WHERE brand_id = ?', [$projectId]);
        $competitorData = $this->buildCompetitorData($aiText, $links, $competitors);

        Response::json([
            'success'          => true,
            'run_id'           => $runId,
            'ai_response'      => nl2br(htmlspecialchars($aiText)),
            'links'            => $links,
            'run_time'         => date('M d, H:i'),
            'brand_mentions'   => $brandMentions,
            'domain_citations' => $domainCitations,
            'competitor_data'  => $competitorData,
            'snapshot_url'     => $result['snapshot_url'],
            'model'            => $result['model_label'],
        ]);
    }

    // ── GET /api/ai-overview/prompts/{promptId}/history ──────────────────────
    public function getHistory(int $promptId): void
    {
        $runs    = $this->db->fetchAll(
            'SELECT id, model, created_at FROM prompt_runs WHERE prompt_id = ? ORDER BY created_at DESC',
            [$promptId]
        );
        $history = array_map(fn($r) => [
            'id'    => $r['id'],
            'model' => $r['model'],
            'time'  => date('M d, Y H:i', strtotime($r['created_at'])),
        ], $runs);

        Response::json(['success' => true, 'history' => $history]);
    }

    // ── GET /api/ai-overview/runs/{runId} ────────────────────────────────────
    public function getRun(int $runId): void
    {
        $run = $this->db->fetch('SELECT * FROM prompt_runs WHERE id = ?', [$runId]);
        if (!$run) {
            Response::error('Run not found', 404);
            return;
        }

        $links = $this->db->fetchAll(
            'SELECT * FROM prompt_run_links WHERE run_id = ? ORDER BY `rank` ASC',
            [$runId]
        );

        $prompt = $this->db->fetch(
            'SELECT bp.brand_id, p.business_name, p.website_url
             FROM brand_prompts bp
             JOIN projects p ON bp.brand_id = p.id
             WHERE bp.id = ?',
            [$run['prompt_id']]
        );

        $nameVars = $prompt ? $this->getNameVariations((int)$prompt['brand_id'], $prompt['business_name']) : [];
        $domVars  = $prompt ? $this->getDomainVariations((int)$prompt['brand_id'], $prompt['website_url']) : [];

        $brandMentions   = AiOverviewHelper::calcBrandMentions($run['ai_response'] ?? '', $nameVars);
        $domainCitations = AiOverviewHelper::calcDomainCitations($links, $domVars);

        $competitors    = $prompt ? $this->db->fetchAll('SELECT * FROM competitors WHERE brand_id = ?', [$prompt['brand_id']]) : [];
        $competitorData = $this->buildCompetitorData($run['ai_response'] ?? '', $links, $competitors);

        Response::json([
            'success'          => true,
            'ai_response'      => nl2br(htmlspecialchars($run['ai_response'] ?? '')),
            'links'            => $links,
            'run_time'         => date('M d, H:i', strtotime($run['created_at'])),
            'model'            => $run['model'],
            'brand_mentions'   => $brandMentions,
            'domain_citations' => $domainCitations,
            'competitor_data'  => $competitorData,
            'snapshot_url'     => $run['snapshot_url'],
        ]);
    }

    // ── GET /api/ai-overview/models ──────────────────────────────────────────
    public function getModels(array $query): void
    {
        $platform  = $query['platform'] ?? 'ChatGPT';
        $allModels = filter_var($query['all'] ?? false, FILTER_VALIDATE_BOOLEAN);
        $models    = AiOverviewHelper::getModels($platform, $allModels);
        Response::json(['success' => true, 'models' => $models]);
    }

    // ── GET /api/projects/{projectId}/ai-overview/competitors ────────────────
    public function listCompetitors(int $projectId): void
    {
        $rows = $this->db->fetchAll('SELECT * FROM competitors WHERE brand_id = ? ORDER BY id ASC', [$projectId]);
        Response::json(['success' => true, 'competitors' => $rows]);
    }

    // ── POST /api/projects/{projectId}/ai-overview/competitors ───────────────
    public function addCompetitor(int $projectId, array $body): void
    {
        $name = trim($body['competitor_name'] ?? '');
        $url  = trim($body['competitor_url']  ?? '');
        if ($name === '' || $url === '') {
            Response::error('Name and URL are required', 400);
            return;
        }
        $id = $this->db->insert('competitors', [
            'brand_id'        => $projectId,
            'competitor_name' => $name,
            'competitor_url'  => $url,
        ]);
        Response::json(['success' => true, 'id' => $id]);
    }

    // ── DELETE /api/ai-overview/competitors/{competitorId} ───────────────────
    public function deleteCompetitor(int $competitorId): void
    {
        $this->db->query('DELETE FROM competitors WHERE id = ?', [$competitorId]);
        Response::json(['success' => true]);
    }

    // ── GET /api/projects/{projectId}/ai-overview/variations ─────────────────
    public function listVariations(int $projectId): void
    {
        $brand  = $this->db->fetchAll('SELECT * FROM brand_variations WHERE brand_id = ?', [$projectId]);
        $domain = $this->db->fetchAll('SELECT * FROM domain_variations WHERE brand_id = ?', [$projectId]);
        Response::json(['success' => true, 'brand_variations' => $brand, 'domain_variations' => $domain]);
    }

    // ── POST /api/projects/{projectId}/ai-overview/variations ────────────────
    public function addVariation(int $projectId, array $body): void
    {
        $type  = $body['type'] ?? '';
        $value = trim($body['value'] ?? '');
        if ($value === '') { Response::error('Value is required', 400); return; }

        if ($type === 'brand') {
            $id = $this->db->insert('brand_variations', ['brand_id' => $projectId, 'variation_name' => $value]);
        } elseif ($type === 'domain') {
            $id = $this->db->insert('domain_variations', ['brand_id' => $projectId, 'variation_domain' => $value]);
        } else {
            Response::error('type must be brand or domain', 400);
            return;
        }
        Response::json(['success' => true, 'id' => $id]);
    }

    // ── DELETE /api/ai-overview/variations/{id} ───────────────────────────────
    public function deleteVariation(int $id, string $type): void
    {
        $table = $type === 'domain' ? 'domain_variations' : 'brand_variations';
        $this->db->query("DELETE FROM {$table} WHERE id = ?", [$id]);
        Response::json(['success' => true]);
    }

    // ── Private helpers ───────────────────────────────────────────────────────

    private function getNameVariations(int $projectId, string $baseName): array
    {
        $extras = $this->db->fetchAll(
            'SELECT variation_name FROM brand_variations WHERE brand_id = ?',
            [$projectId]
        );
        $names  = array_column($extras, 'variation_name');
        if ($baseName !== '') $names[] = $baseName;
        return array_filter($names);
    }

    private function getDomainVariations(int $projectId, string $baseUrl): array
    {
        $extras  = $this->db->fetchAll(
            'SELECT variation_domain FROM domain_variations WHERE brand_id = ?',
            [$projectId]
        );
        $domains = array_column($extras, 'variation_domain');
        if ($baseUrl !== '') {
            $domains[] = $baseUrl;
            $domains[] = AiOverviewHelper::normaliseDomain($baseUrl);
        }
        return array_filter(array_unique($domains));
    }

    private function buildCompetitorData(string $aiText, array $links, array $competitors): array
    {
        $clean = strtolower($aiText);
        $data  = [];
        foreach ($competitors as $c) {
            $mentions = $c['competitor_name']
                ? substr_count($clean, strtolower($c['competitor_name']))
                : 0;

            $cDomain = strtolower(preg_replace('#^https?://(www\.)?#', '', rtrim($c['competitor_url'] ?? '', '/')));
            $cLinks  = [];
            if ($cDomain) {
                foreach ($links as $link) {
                    if (strpos(strtolower($link['domain'] ?? ''), $cDomain) !== false) {
                        $cLinks[] = $link;
                    }
                }
            }
            $data[] = [
                'name'      => $c['competitor_name'],
                'url'       => $c['competitor_url'],
                'mentions'  => $mentions,
                'citations' => count($cLinks),
                'links'     => $cLinks,
            ];
        }
        return $data;
    }
}
