<?php
declare(strict_types=1);
// ==================================================
// Nuclear Fancy Pants Edition™ -- NUCLEAR+++
// File: /home/ploi/automarketer-ai.com/public/wp-content/plugins/automarketer-ai/includes/class-ga4-sync.php
// Description: GA4 metrics sync -- daily cron pulls per-page sessions and pageviews from GA4 Data API - NUCLEAR+++
// Last Edited: 2026-05-18
// ==================================================

namespace AutoMarketerAI;

defined('ABSPATH') || exit;

final class Ga4Sync
{
    private const DATA_API_BASE = 'https://analyticsdata.googleapis.com/v1beta';
    public const CRON_HOOK      = 'amai_ga4_sync';

    // --------------------------------------------------
    // Register hooks
    // --------------------------------------------------
    public static function register(): void
    {
        add_action(self::CRON_HOOK, [self::class, 'run']);
    }

    // --------------------------------------------------
    // Schedule/unschedule cron
    // --------------------------------------------------
    public static function scheduleCron(): void
    {
        if (!wp_next_scheduled(self::CRON_HOOK)) {
            wp_schedule_event(time(), 'daily', self::CRON_HOOK);
        }
    }

    public static function unscheduleCron(): void
    {
        $ts = wp_next_scheduled(self::CRON_HOOK);
        if ($ts !== false) {
            wp_unschedule_event($ts, self::CRON_HOOK);
        }
    }

    // --------------------------------------------------
    // Main sync -- called by cron
    // --------------------------------------------------
    public static function run(): void
    {
        if (!Ga4Auth::isConnected()) {
            return;
        }

        $accessToken = Ga4Auth::getAccessToken();
        if ($accessToken === null) {
            return;
        }

        $propertyId = Ga4Auth::getPropertyId();
        if ($propertyId === null) {
            return;
        }

        $published = get_posts([
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'posts_per_page' => -1,
            'fields'         => 'ids',
        ]);

        if (empty($published)) {
            return;
        }

        // Build path => post_id map
        $path_map = [];
        foreach ($published as $post_id) {
            $permalink = get_permalink((int) $post_id);
            if (!is_string($permalink) || $permalink === '') {
                continue;
            }
            $parsed = parse_url($permalink, PHP_URL_PATH);
            if (is_string($parsed) && $parsed !== '') {
                $path_map[$parsed] = (int) $post_id;
            }
        }

        if (empty($path_map)) {
            return;
        }

        $now       = gmdate('Y-m-d');
        $start_30d = gmdate('Y-m-d', strtotime('-30 days'));
        $start_60d = gmdate('Y-m-d', strtotime('-60 days'));
        $end_31d   = gmdate('Y-m-d', strtotime('-31 days'));

        // Fetch current 30-day window
        $current = self::fetchReport($accessToken, $propertyId, $start_30d, $now);
        if ($current === null) {
            return;
        }

        // Fetch previous 30-day window (days -60 to -31)
        $previous = self::fetchReport($accessToken, $propertyId, $start_60d, $end_31d);
        if ($previous === null) {
            $previous = [];
        }

        self::storeMetrics($path_map, $current, $previous);

        // Update last_synced_at on connection
        global $wpdb;
        $wpdb->update(
            $wpdb->prefix . 'amai_ga4_connection',
            ['last_synced_at' => gmdate('Y-m-d H:i:s')],
            ['tenant_id' => (string) get_option('amai_tenant_id', 'default')]
        );
    }

    // --------------------------------------------------
    // Fetch a GA4 runReport for sessions + pageviews by pagePath
    // Returns array keyed by pagePath or null on failure
    // --------------------------------------------------
    private static function fetchReport(
        string $accessToken,
        string $propertyId,
        string $start_date,
        string $end_date
    ): ?array {
        $payload = json_encode([
            'dateRanges' => [
                ['startDate' => $start_date, 'endDate' => $end_date],
            ],
            'dimensions' => [
                ['name' => 'pagePath'],
            ],
            'metrics' => [
                ['name' => 'sessions'],
                ['name' => 'screenPageViews'],
            ],
            'limit' => 1000,
        ]);

        if ($payload === false) {
            return null;
        }

        $url      = self::DATA_API_BASE . '/' . $propertyId . ':runReport';
        $response = wp_remote_post($url, [
            'timeout' => 30,
            'headers' => [
                'Authorization' => 'Bearer ' . $accessToken,
                'Content-Type'  => 'application/json',
            ],
            'body' => $payload,
        ]);

        if (is_wp_error($response)) {
            return null;
        }

        $httpCode = (int) wp_remote_retrieve_response_code($response);
        $json     = json_decode(wp_remote_retrieve_body($response), true);

        if ($httpCode !== 200 || !is_array($json) || empty($json['rows'])) {
            return [];
        }

        $result = [];
        foreach ($json['rows'] as $row) {
            $path      = (string) ($row['dimensionValues'][0]['value'] ?? '');
            $sessions  = (int) ($row['metricValues'][0]['value'] ?? 0);
            $pageviews = (int) ($row['metricValues'][1]['value'] ?? 0);
            if ($path !== '') {
                $result[$path] = [
                    'sessions'  => $sessions,
                    'pageviews' => $pageviews,
                ];
            }
        }

        return $result;
    }

    // --------------------------------------------------
    // Store metrics to wp_amai_ga4_metrics
    // --------------------------------------------------
    private static function storeMetrics(array $path_map, array $current, array $previous): void
    {
        global $wpdb;
        $table = $wpdb->prefix . 'amai_ga4_metrics';
        $now   = gmdate('Y-m-d H:i:s');

        foreach ($path_map as $path => $post_id) {
            $curr = $current[$path] ?? ['sessions' => 0, 'pageviews' => 0];
            $prev = $previous[$path] ?? ['sessions' => 0, 'pageviews' => 0];

            $existing = $wpdb->get_var(
                $wpdb->prepare("SELECT id FROM `{$table}` WHERE post_id = %d LIMIT 1", $post_id)
            );

            $data = [
                'ga_page_path'       => $path,
                'sessions_30d'       => $curr['sessions'],
                'sessions_prev_30d'  => $prev['sessions'],
                'pageviews_30d'      => $curr['pageviews'],
                'pageviews_prev_30d' => $prev['pageviews'],
                'last_synced_at'     => $now,
            ];

            if ($existing !== null) {
                $wpdb->update($table, $data, ['post_id' => $post_id]);
            } else {
                $data['post_id'] = $post_id;
                $wpdb->insert($table, $data);
            }
        }
    }

    // --------------------------------------------------
    // Get metrics for a single post -- used by Content Health tab
    // Returns array with sessions_30d, sessions_prev_30d, pageviews_30d,
    // pageviews_prev_30d, trend ('up'|'down'|'flat'), last_synced_at
    // or null if no data exists
    // --------------------------------------------------
    public static function getPostMetrics(int $post_id): ?array
    {
        global $wpdb;
        $table = $wpdb->prefix . 'amai_ga4_metrics';

        if ($wpdb->get_var("SHOW TABLES LIKE '{$table}'") !== $table) {
            return null;
        }

        $row = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM `{$table}` WHERE post_id = %d LIMIT 1",
                $post_id
            ),
            ARRAY_A
        );

        if (!is_array($row)) {
            return null;
        }

        $curr = (int) $row['sessions_30d'];
        $prev = (int) $row['sessions_prev_30d'];

        if ($prev === 0) {
            $trend = $curr > 0 ? 'up' : 'flat';
        } elseif ($curr > $prev) {
            $trend = 'up';
        } elseif ($curr < $prev) {
            $trend = 'down';
        } else {
            $trend = 'flat';
        }

        $row['trend'] = $trend;
        return $row;
    }

    // --------------------------------------------------
    // Get decaying posts -- sessions trending down or zero
    // with at least MIN_AGE_DAYS since publish
    // --------------------------------------------------
    public static function getDecayingPosts(int $min_age_days = 180, int $limit = 20): array
    {
        global $wpdb;
        $table      = $wpdb->prefix . 'amai_ga4_metrics';
        $posts_table = $wpdb->posts;

        if ($wpdb->get_var("SHOW TABLES LIKE '{$table}'") !== $table) {
            return [];
        }

        $cutoff = gmdate('Y-m-d', strtotime('-' . $min_age_days . ' days'));

        $rows = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT m.*, p.post_title, p.post_date, p.post_modified
                 FROM `{$table}` m
                 INNER JOIN `{$posts_table}` p ON p.ID = m.post_id
                 WHERE p.post_status = 'publish'
                 AND p.post_type = 'post'
                 AND p.post_date <= %s
                 AND (
                     m.sessions_30d < m.sessions_prev_30d
                     OR (m.sessions_30d = 0 AND m.sessions_prev_30d = 0)
                 )
                 ORDER BY m.sessions_30d ASC
                 LIMIT %d",
                $cutoff,
                $limit
            ),
            ARRAY_A
        );

        if (!is_array($rows)) {
            return [];
        }

        foreach ($rows as &$row) {
            $curr  = (int) $row['sessions_30d'];
            $prev  = (int) $row['sessions_prev_30d'];
            $row['trend']        = ($prev > 0 && $curr < $prev) ? 'down' : 'flat';
            $row['days_old']     = (int) floor((time() - strtotime((string) $row['post_date'])) / DAY_IN_SECONDS);
            $row['last_updated'] = (int) floor((time() - strtotime((string) $row['post_modified'])) / DAY_IN_SECONDS);
            $row['edit_url']     = (string) get_edit_post_link((int) $row['post_id'], 'raw');
            $row['view_url']     = (string) get_permalink((int) $row['post_id']);
        }
        unset($row);

        return $rows;
    }
}