<?php

/**
 * Analytics - Aggregated stats recorder & statistics manager for CodePress CMS
 */
class Analytics
{
    private string $statsFile;
    private array $config;

    public function __construct(array $analyticsConfig = [])
    {
        $this->config = $analyticsConfig;
        $this->statsFile = dirname(__DIR__, 3) . '/admin/storage/stats.json';
        $dir = dirname($this->statsFile);
        if (!is_dir($dir)) {
            @mkdir($dir, 0755, true);
        }
    }

    /**
     * Record a page visit in aggregated stats.json
     *
     * @param string $page Page key
     * @param string $ip Client IP
     * @param string $userAgent User Agent string
     * @param string $referrer Referrer string
     * @param string $country Resolved country code (e.g. NL, BE)
     * @param string $status Status string (ok, blocked:ai, blocked:ratelimit, etc.)
     */
    public function record(string $page, string $ip, string $userAgent, string $referrer, ?string $country, string $status): void
    {
        if (empty($this->config['enabled'])) {
            return;
        }

        $today = date('Y-m-d');
        $country = ($country && strlen($country) === 2) ? strtoupper($country) : 'UNKNOWN';
        $isBlocked = str_starts_with($status, 'blocked');

        // Identify bot vs human
        $visitorInfo = RequestLogger::detectVisitorInfo($userAgent);
        $type = $visitorInfo['type'];
        $isBot = in_array($type, ['ai', 'search', 'scraper', 'bot'], true);

        // Anonymized unique IP salt per day
        $ipSalt = date('Y-m-d') . '_codepress_salt';
        $ipHash = md5($ip . $ipSalt);

        // Domain/host from referrer
        $refHost = 'direct';
        if ($referrer !== '') {
            $parsed = parse_url($referrer);
            if (!empty($parsed['host'])) {
                $refHost = preg_replace('/^www\./', '', strtolower($parsed['host']));
            }
        }

        // Open stats.json with exclusive lock
        $handle = @fopen($this->statsFile, 'c+');
        if (!$handle) return;

        if (flock($handle, LOCK_EX)) {
            $fileSize = filesize($this->statsFile);
            $data = [];
            if ($fileSize > 0) {
                $content = fread($handle, $fileSize);
                $data = json_decode($content, true);
            }
            if (!is_array($data)) {
                $data = [
                    'totals' => ['views' => 0, 'human' => 0, 'bot' => 0, 'blocked' => 0],
                    'countries' => [],
                    'pages' => [],
                    'referrers' => [],
                    'days' => [],
                    'uniques' => []
                ];
            }

            // Totals
            $data['totals']['views'] = ($data['totals']['views'] ?? 0) + 1;
            if ($isBlocked) {
                $data['totals']['blocked'] = ($data['totals']['blocked'] ?? 0) + 1;
            } elseif ($isBot) {
                $data['totals']['bot'] = ($data['totals']['bot'] ?? 0) + 1;
            } else {
                $data['totals']['human'] = ($data['totals']['human'] ?? 0) + 1;
            }

            // Countries
            $data['countries'][$country] = ($data['countries'][$country] ?? 0) + 1;

            // Pages
            $data['pages'][$page] = ($data['pages'][$page] ?? 0) + 1;

            // Referrers
            if ($refHost !== 'direct') {
                $data['referrers'][$refHost] = ($data['referrers'][$refHost] ?? 0) + 1;
            }

            // Day stats
            if (!isset($data['days'][$today])) {
                $data['days'][$today] = ['views' => 0, 'human' => 0, 'bot' => 0, 'blocked' => 0, 'countries' => [], 'pages' => []];
            }
            $data['days'][$today]['views']++;
            if ($isBlocked) {
                $data['days'][$today]['blocked']++;
            } elseif ($isBot) {
                $data['days'][$today]['bot']++;
            } else {
                $data['days'][$today]['human']++;
            }
            $data['days'][$today]['countries'][$country] = ($data['days'][$today]['countries'][$country] ?? 0) + 1;
            $data['days'][$today]['pages'][$page] = ($data['days'][$today]['pages'][$page] ?? 0) + 1;

            // Uniques per day
            if (!isset($data['uniques'][$today])) {
                $data['uniques'][$today] = [];
            }
            if (!in_array($ipHash, $data['uniques'][$today], true)) {
                $data['uniques'][$today][] = $ipHash;
            }

            // Cleanup retention (keep max retention_days)
            $retentionDays = max(30, (int)($this->config['retention_days'] ?? 400));
            $cutoffDate = date('Y-m-d', strtotime("-{$retentionDays} days"));

            foreach (array_keys($data['days']) as $d) {
                if ($d < $cutoffDate) {
                    unset($data['days'][$d]);
                    unset($data['uniques'][$d]);
                }
            }

            // Rewrite stats file
            ftruncate($handle, 0);
            rewind($handle);
            fwrite($handle, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
            fflush($handle);
            flock($handle, LOCK_UN);
        }

        fclose($handle);
    }

    /**
     * Get aggregated statistics data for a specific period
     *
     * @param int $days Number of days (e.g. 7, 30, 90, 0 for all)
     * @return array Aggregated stats
     */
    public function getStats(int $days = 30): array
    {
        if (!file_exists($this->statsFile)) {
            return [
                'totals' => ['views' => 0, 'human' => 0, 'bot' => 0, 'blocked' => 0, 'uniques' => 0],
                'countries' => [],
                'pages' => [],
                'referrers' => [],
                'daily_chart' => [],
            ];
        }

        $raw = json_decode(file_get_contents($this->statsFile), true);
        if (!is_array($raw)) $raw = [];

        if ($days === 0) {
            // All time
            $countries = $raw['countries'] ?? [];
            $pages = $raw['pages'] ?? [];
            $referrers = $raw['referrers'] ?? [];
            $totals = $raw['totals'] ?? ['views' => 0, 'human' => 0, 'bot' => 0, 'blocked' => 0];

            $totalUniques = 0;
            foreach ($raw['uniques'] ?? [] as $uList) {
                $totalUniques += count($uList);
            }
            $totals['uniques'] = $totalUniques;

            $dailyChart = [];
            foreach ($raw['days'] ?? [] as $date => $dData) {
                $dailyChart[$date] = [
                    'date' => $date,
                    'views' => $dData['views'] ?? 0,
                    'human' => $dData['human'] ?? 0,
                    'uniques' => count($raw['uniques'][$date] ?? [])
                ];
            }
            ksort($dailyChart);

            arsort($countries);
            arsort($pages);
            arsort($referrers);

            return [
                'totals' => $totals,
                'countries' => $countries,
                'pages' => $pages,
                'referrers' => $referrers,
                'daily_chart' => array_values($dailyChart)
            ];
        }

        // Filtered by last $days days
        $cutoff = date('Y-m-d', strtotime("-{$days} days"));
        $filteredCountries = [];
        $filteredPages = [];
        $filteredTotals = ['views' => 0, 'human' => 0, 'bot' => 0, 'blocked' => 0, 'uniques' => 0];
        $dailyChart = [];

        foreach ($raw['days'] ?? [] as $date => $dData) {
            if ($date >= $cutoff) {
                $v = $dData['views'] ?? 0;
                $h = $dData['human'] ?? 0;
                $b = $dData['bot'] ?? 0;
                $bl = $dData['blocked'] ?? 0;
                $u = count($raw['uniques'][$date] ?? []);

                $filteredTotals['views'] += $v;
                $filteredTotals['human'] += $h;
                $filteredTotals['bot'] += $b;
                $filteredTotals['blocked'] += $bl;
                $filteredTotals['uniques'] += $u;

                foreach ($dData['countries'] ?? [] as $c => $cnt) {
                    $filteredCountries[$c] = ($filteredCountries[$c] ?? 0) + $cnt;
                }
                foreach ($dData['pages'] ?? [] as $p => $cnt) {
                    $filteredPages[$p] = ($filteredPages[$p] ?? 0) + $cnt;
                }

                $dailyChart[$date] = [
                    'date' => $date,
                    'views' => $v,
                    'human' => $h,
                    'uniques' => $u
                ];
            }
        }

        // Fill missing dates in range for smooth chart
        for ($i = $days - 1; $i >= 0; $i--) {
            $dStr = date('Y-m-d', strtotime("-{$i} days"));
            if (!isset($dailyChart[$dStr])) {
                $dailyChart[$dStr] = ['date' => $dStr, 'views' => 0, 'human' => 0, 'uniques' => 0];
            }
        }
        ksort($dailyChart);

        arsort($filteredCountries);
        arsort($filteredPages);

        $referrers = $raw['referrers'] ?? [];
        arsort($referrers);

        return [
            'totals' => $filteredTotals,
            'countries' => $filteredCountries,
            'pages' => $filteredPages,
            'referrers' => $referrers,
            'daily_chart' => array_values($dailyChart)
        ];
    }
}
