<?php
/**
 * @package         FireBox
 * @version         3.1.1 Pro
 * 
 * @author          FirePlugins <info@fireplugins.com>
 * @link            https://www.fireplugins.com
 * @copyright       Copyright © 2025 FirePlugins All Rights Reserved
 * @license         GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/

namespace FireBox\Core\RevenueAttribution;

if (!defined('ABSPATH'))
{
	exit; // Exit if accessed directly.
}

class Ajax
{
    public function __construct()
    {
        add_action('wp_ajax_firebox_analytics_lifetime_revenue', [$this, 'firebox_analytics_lifetime_revenue']);
        add_action('wp_ajax_nopriv_firebox_analytics_lifetime_revenue', [$this, 'firebox_analytics_lifetime_revenue']);
        
        add_action('wp_ajax_firebox_analytics_sales_funnel', [$this, 'firebox_analytics_sales_funnel']);
        add_action('wp_ajax_nopriv_firebox_analytics_sales_funnel', [$this, 'firebox_analytics_sales_funnel']);
    }

    /**
     * Get lifetime revenue data for Pro+ plan users
     * 
     * @return  void
     */
    public function firebox_analytics_lifetime_revenue()
    {
        if (!current_user_can('manage_options'))
        {
            return;
        }
        
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        // verify nonce
        if (!$verify = wp_verify_nonce($nonce, 'fpf_js_nonce'))
        {
            return false;
        }

        $selected_campaign = isset($_POST['selected_campaign']) && !empty($_POST['selected_campaign']) ? intval(wp_unslash($_POST['selected_campaign'])) : '';
        
        // Use the existing Revenue metric class to get lifetime revenue
        // Set a very wide date range to get all-time data
        $start_date = '2020/01/01 00:00:00'; // Far back start date
        $end_date = date('Y/m/d 23:59:59'); // Today's end
        
        $revenueMetric = new \FireBox\Core\Analytics\Metrics\Revenue($start_date, $end_date, 'count');
        
        if ($selected_campaign) {
            $revenueMetric->filters([
                'campaign' => [
                    'value' => [$selected_campaign]
                ]
            ]);
        }
        
        $lifetime_revenue = $revenueMetric->getData('count');

        echo wp_json_encode([
            'lifetime_revenue' => floatval($lifetime_revenue)
        ]);
        wp_die();
    }

    /**
     * Get sales funnel data for Pro+ plan users
     * Views → Clicks → Conversions → Purchases
     * 
     * @return  void
     */
    public function firebox_analytics_sales_funnel()
    {
        if (!current_user_can('manage_options'))
        {
            return;
        }
		
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
		
        // verify nonce
        if (!$verify = wp_verify_nonce($nonce, 'fpf_js_nonce'))
        {
            return false;
        }

        $start_date = isset($_POST['start_date']) ? sanitize_text_field(wp_unslash($_POST['start_date'])) : '';
        $end_date = isset($_POST['end_date']) ? sanitize_text_field(wp_unslash($_POST['end_date'])) : '';

        if (!$start_date || $start_date === 'false' || !$end_date || $end_date === 'false')
        {
            return;
        }

        \FireBox\Core\Analytics\Helpers\Date::transformStartEndDateToUTC($start_date, $end_date);
		
        $selected_campaign = isset($_POST['selected_campaign']) && !empty($_POST['selected_campaign']) ? intval(wp_unslash($_POST['selected_campaign'])) : null;

        // Build sales funnel step by step
        $funnelData = $this->buildSalesFunnel($start_date, $end_date, $selected_campaign);

        echo wp_json_encode($funnelData);
        wp_die();
    }

    /**
     * Build complete sales funnel: Views → Clicks → Conversions → Purchases
     * 
     * @param string $start_date UTC start date
     * @param string $end_date UTC end date  
     * @param int $selected_campaign Campaign ID filter
     * @return array Funnel data with views, clicks, conversions, purchases
     */
    private function buildSalesFunnel($start_date, $end_date, $selected_campaign = null)
    {
        $views = $this->getViews($start_date, $end_date, $selected_campaign);

        if ($views === 0) {
            return $this->getEmptyFunnel();
        }

        $clicks = $this->getClicks($start_date, $end_date, $selected_campaign);

        if ($clicks === 0) {
            return $this->getFunnelWithViews($views);
        }

        $conversions = $this->getConversions($start_date, $end_date, $selected_campaign);

        if ($conversions === 0) {
            return $this->getFunnelWithViewsAndClicks($views, $clicks);
        }

        $purchases_data = $this->getPurchases($start_date, $end_date, $selected_campaign);

        return [
            'views' => intval($views),
            'clicks' => intval($clicks),
            'conversions' => intval($conversions),
            'purchases' => intval($purchases_data['count']),
            'purchases_amount' => $purchases_data['amount']
        ];
    }

    /**
     * Get total views (impressions) for the period
     * 
     * @param string $start_date UTC start date
     * @param string $end_date UTC end date
     * @param int $selected_campaign Campaign ID filter
     * @return int
     */
    private function getViews($start_date, $end_date, $selected_campaign = null)
    {
        global $wpdb;
		
        $views_subquery = $this->getViewLogIdsSubquery($start_date, $end_date, $selected_campaign);
		
        $query = "
            SELECT COUNT(*)
            FROM ({$views_subquery}) views
        ";

        return intval($wpdb->get_var($query));
    }

    /**
     * Get clicks within the selected period ensuring they originate from tracked views
     * 
     * @param string $start_date UTC start date
     * @param string $end_date UTC end date
     * @param int $selected_campaign Campaign ID filter
     * @return int
     */
    private function getClicks($start_date, $end_date, $selected_campaign = null)
    {
        global $wpdb;
		
        $clicks_subquery = $this->getClickLogIdsSubquery($start_date, $end_date, $selected_campaign);
		
        $query = "
            SELECT COUNT(*)
            FROM ({$clicks_subquery}) clicks
        ";

        return intval($wpdb->get_var($query));
    }

    /**
     * Get conversions restricted to logs that produced clicks
     * 
     * @param string $start_date UTC start date
     * @param string $end_date UTC end date
     * @param int $selected_campaign Campaign ID filter
     * @return int
     */
    private function getConversions($start_date, $end_date, $selected_campaign = null)
    {
        global $wpdb;
		
        $conversions_subquery = $this->getConversionLogIdsSubquery($start_date, $end_date, $selected_campaign);
		
        $query = "
            SELECT COUNT(*)
            FROM ({$conversions_subquery}) conversions
        ";

        return intval($wpdb->get_var($query));
    }

    /**
     * Get purchases restricted to logs that completed conversions
     * 
     * @param string $start_date UTC start date
     * @param string $end_date UTC end date
     * @param int $selected_campaign Campaign ID filter
     * @return array ['count' => int, 'amount' => float]
     */
    private function getPurchases($start_date, $end_date, $selected_campaign = null)
    {
        global $wpdb;
		
        $conversions_subquery = $this->getConversionLogIdsSubquery($start_date, $end_date, $selected_campaign);
		
        // When filtering by campaign, we need global counts for multi-touch attribution
        // This subquery calculates how many campaigns contributed to each order (globally, not filtered)
        $query = "
            SELECT 
                JSON_EXTRACT(ld.event_label, '$.order_type') as order_type,
                JSON_EXTRACT(ld.event_label, '$.order_id') as order_id,
                ld.event_source,
                counts.global_conversion_count,
                counts.global_impression_count
            FROM {$wpdb->prefix}firebox_logs_details ld
            INNER JOIN ({$conversions_subquery}) conversions ON conversions.log_id = ld.log_id
            LEFT JOIN (
                SELECT 
                    JSON_EXTRACT(bld2.event_label, '$.order_id') as order_id,
                    JSON_EXTRACT(bld2.event_label, '$.order_type') as order_type,
                    SUM(CASE WHEN bld2.event = 'revenue' AND bld2.event_source = 'conversion' THEN 1 ELSE 0 END) as global_conversion_count,
                    SUM(CASE WHEN bld2.event = 'revenue' AND bld2.event_source = 'impression' THEN 1 ELSE 0 END) as global_impression_count
                FROM {$wpdb->prefix}firebox_logs_details bld2
                WHERE bld2.event = 'revenue'
                GROUP BY JSON_EXTRACT(bld2.event_label, '$.order_id'), JSON_EXTRACT(bld2.event_label, '$.order_type')
            ) counts ON counts.order_id = JSON_EXTRACT(ld.event_label, '$.order_id') 
                     AND counts.order_type = JSON_EXTRACT(ld.event_label, '$.order_type')
            WHERE ld.event = 'revenue'
              AND ld.event_source = 'conversion'
              AND ld.date >= %s AND ld.date <= %s
              AND JSON_VALID(ld.event_label)
              AND JSON_EXTRACT(ld.event_label, '$.order_id') IS NOT NULL
        ";
		
        $params = [$start_date, $end_date];
        $rows = $wpdb->get_results($wpdb->prepare($query, $params));
        
        // Reuse Revenue class's attribution logic
        $revenueMetric = new \FireBox\Core\Analytics\Metrics\Revenue($start_date, $end_date, 'count');
        
        if ($selected_campaign) {
            $revenueMetric->filters([
                'campaign' => [
                    'value' => [$selected_campaign]
                ]
            ]);
        }
        
        // Use Revenue's method to calculate attributed revenue
        $total_amount = $revenueMetric->calculateTotalRevenue($rows);
        
        // Use Revenue's method to build order map and get count
        $orderMap = $this->buildOrderMapForCount($rows);
        $purchases_count = count($orderMap);
		
        return [
            'count' => $purchases_count,
            'amount' => $total_amount
        ];
    }

    /**
     * Build base views subquery for reuse across funnel stages
     * 
     * @param string $start_date
     * @param string $end_date
     * @param int|null $selected_campaign
     * @return string Prepared SQL subquery returning `log_id`
     */
    private function getViewLogIdsSubquery($start_date, $end_date, $selected_campaign = null)
    {
        global $wpdb;
		
        $query = "
            SELECT l.id AS log_id
            FROM {$wpdb->prefix}firebox_logs l
            WHERE l.date >= %s AND l.date <= %s
        ";
		
        $params = [$start_date, $end_date];
		
        if ($selected_campaign) {
            $query .= " AND l.box = %d";
            $params[] = $selected_campaign;
        }

        return $wpdb->prepare($query, $params);
    }

    /**
     * Build click subquery filtered by views dataset
     * 
     * @param string $start_date
     * @param string $end_date
     * @param int|null $selected_campaign
     * @return string Prepared SQL subquery returning distinct `log_id`
     */
    private function getClickLogIdsSubquery($start_date, $end_date, $selected_campaign = null)
    {
        global $wpdb;
		
        $views_subquery = $this->getViewLogIdsSubquery($start_date, $end_date, $selected_campaign);
		
        $query = "
            SELECT DISTINCT ld.log_id AS log_id
            FROM {$wpdb->prefix}firebox_logs_details ld
            INNER JOIN ({$views_subquery}) views ON views.log_id = ld.log_id
            WHERE ld.event = 'click'
              AND ld.date >= %s AND ld.date <= %s
        ";
		
        $params = [$start_date, $end_date];

        return $wpdb->prepare($query, $params);
    }

    /**
     * Build conversion subquery filtered by click dataset
     * 
     * @param string $start_date
     * @param string $end_date
     * @param int|null $selected_campaign
     * @return string Prepared SQL subquery returning distinct `log_id`
     */
    private function getConversionLogIdsSubquery($start_date, $end_date, $selected_campaign = null)
    {
        global $wpdb;
		
        $clicks_subquery = $this->getClickLogIdsSubquery($start_date, $end_date, $selected_campaign);
		
        $query = "
            SELECT DISTINCT ld.log_id AS log_id
            FROM {$wpdb->prefix}firebox_logs_details ld
            INNER JOIN ({$clicks_subquery}) clicks ON clicks.log_id = ld.log_id
            WHERE ld.event = 'conversion'
              AND ld.date >= %s AND ld.date <= %s
        ";
		
        $params = [$start_date, $end_date];

        return $wpdb->prepare($query, $params);
    }

    /**
     * Get empty funnel data (all zeros)
     * 
     * @return array
     */
    private function getEmptyFunnel()
    {
        return [
            'views' => 0,
            'clicks' => 0,
            'conversions' => 0,
            'purchases' => 0,
            'purchases_amount' => 0
        ];
    }

    /**
     * Get funnel data with only views (rest zeros)
     * 
     * @param int $views
     * @return array
     */
    private function getFunnelWithViews($views)
    {
        return [
            'views' => intval($views),
            'clicks' => 0,
            'conversions' => 0,
            'purchases' => 0,
            'purchases_amount' => 0
        ];
    }

    /**
     * Get funnel data with views and clicks (rest zeros)
     * 
     * @param int $views
     * @param int $clicks
     * @return array
     */
    private function getFunnelWithViewsAndClicks($views, $clicks)
    {
        return [
            'views' => intval($views),
            'clicks' => intval($clicks),
            'conversions' => 0,
            'purchases' => 0,
            'purchases_amount' => 0
        ];
    }

    /**
     * Build a simple order map to count unique orders
     * 
     * @param array $results Database results
     * @return array Map of unique order keys
     */
    private function buildOrderMapForCount($results)
    {
        $orderMap = [];
        
        if (!is_array($results)) {
            return $orderMap;
        }
        
        foreach ($results as $result) {
            $order_type = trim($result->order_type ?? '', '"');
            $order_id = intval(trim($result->order_id ?? '', '"'));
            
            if (empty($order_id)) {
                continue;
            }
            
            $order_key = $order_type . '_' . $order_id;
            $orderMap[$order_key] = true;
        }
        
        return $orderMap;
    }
}