<?php

namespace fluXtore\Core\Frontend;

use fluXtore\Core\Settings\fluXtore_Google_Analytics_Settings;
use fluXtore\Core\Settings\fluXtore_Settings;

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

if ( ! class_exists( 'fluXtore_Google_Analytics' ) ) {
        class fluXtore_Google_Analytics {
                /**
                 * @var self|null
                 */
                private static $instance = null;

                /**
                 * @var string
                 */
                private $measurement_id = '';

                /**
                 * @var array
                 */
                private $events = [];

                /**
                 * @var array
                 */
                private $config = [];

                /**
                 * @var array<int,bool>
                 */
                private $processed_orders = [];

                /**
                 * @var bool
                 */
                private $has_rendered = false;

                private function __construct() {}

                public static function init() {
                        if ( null !== self::$instance ) {
                                return;
                        }

                        self::$instance = new self();
                        self::$instance->register_hooks();
                }

                private function register_hooks() {
                        add_action( 'wp_head', [ $this, 'render_script' ] );
                        add_action( 'woocommerce_thankyou', [ $this, 'output_purchase_event' ], 20, 1 );
                }

                public function render_script() {
                        if ( $this->has_rendered ) {
                                return;
                        }

                        if ( is_admin() || ( function_exists( 'wp_doing_ajax' ) && wp_doing_ajax() ) ) {
                                return;
                        }

                        if ( fluXtore_Tracking_Helper::is_builder_preview() ) {
                                return;
                        }

                        $this->measurement_id = $this->get_measurement_id();

                        if ( '' === $this->measurement_id ) {
                                return;
                        }

                        if ( ! fluXtore_Tracking_Helper::is_relevant_context() ) {
                                return;
                        }

                        $this->events = $this->get_events_config();

                        $config = $this->build_config();
                        $config = apply_filters( 'fluxtore_google_analytics_config', $config );

                        $should_track_page_view = ! empty( $config['events']['page_view'] );
                        $should_track_checkout  = ! empty( $config['events']['begin_checkout'] )
                                && fluXtore_Tracking_Helper::is_checkout_context( $config['step']['tag'] ?? null );

                        $page_view_payload      = [];
                        $begin_checkout_payload = [];
                        $payloads               = [];

                        if ( $should_track_page_view ) {
                                $page_view_payload        = $this->build_page_view_payload( $config );
                                $payloads['page_view']    = $page_view_payload;
                        }

                        if ( $should_track_checkout ) {
                                $begin_checkout_payload   = $this->build_begin_checkout_payload( $config );
                                $payloads['begin_checkout'] = $begin_checkout_payload;
                        }

                        if ( ! empty( $payloads ) ) {
                                $payloads = apply_filters( 'fluxtore_google_analytics_payloads', $payloads, $config );
                                $page_view_payload        = $payloads['page_view'] ?? $page_view_payload;
                                $begin_checkout_payload   = $payloads['begin_checkout'] ?? $begin_checkout_payload;
                                $config['payloads']       = $payloads;
                        }

                        $this->config = $config;

                        $config_args = [
                                'send_page_view' => false,
                        ];

                        if ( ! empty( $config['currency'] ) ) {
                                $config_args['currency'] = $config['currency'];
                        }

                        $config_args = apply_filters( 'fluxtore_google_analytics_config_args', $config_args, $config );

                        $config_json       = wp_json_encode( $config );
                        $config_args_json  = wp_json_encode( $config_args );
                        $page_view_json    = $should_track_page_view ? wp_json_encode( $page_view_payload ) : '';
                        $begin_checkout_json = $should_track_checkout ? wp_json_encode( $begin_checkout_payload ) : '';

                        $config_json       = false !== $config_json ? $config_json : '{}';
                        $config_args_json  = false !== $config_args_json ? $config_args_json : '{}';
                        $page_view_json    = false !== $page_view_json && '' !== $page_view_json ? $page_view_json : '{}';
                        $begin_checkout_json = false !== $begin_checkout_json && '' !== $begin_checkout_json ? $begin_checkout_json : '{}';

                        $script_src = sprintf( 'https://www.googletagmanager.com/gtag/js?id=%s', rawurlencode( $this->measurement_id ) );
                        $measurement_id_js = esc_js( $this->measurement_id );

                        $this->has_rendered = true;

                        ?>
<!-- fluXtore Google Analytics 4 -->
<script async src="<?php echo esc_url( $script_src ); ?>"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
window.fluxtoreGoogleAnalytics = Object.assign({}, window.fluxtoreGoogleAnalytics || {}, <?php echo $config_json; ?>);
gtag('js', new Date());
gtag('config', '<?php echo $measurement_id_js; ?>', <?php echo $config_args_json; ?>);
<?php if ( $should_track_page_view ) : ?>
gtag('event', 'page_view', <?php echo $page_view_json; ?>);
<?php endif; ?>
<?php if ( $should_track_checkout ) : ?>
gtag('event', 'begin_checkout', <?php echo $begin_checkout_json; ?>);
<?php endif; ?>
</script>
<!-- End fluXtore Google Analytics 4 -->
                        <?php

                        do_action( 'fluxtore_google_analytics_rendered', $config );
                }

                public function output_purchase_event( $order_id ) {
                        if ( empty( $order_id ) ) {
                                return;
                        }

                        if ( function_exists( 'wp_doing_ajax' ) && wp_doing_ajax() ) {
                                return;
                        }

                        if ( isset( $this->processed_orders[ $order_id ] ) ) {
                                return;
                        }

                        $this->processed_orders[ $order_id ] = true;

                        $this->events = ! empty( $this->events ) ? $this->events : $this->get_events_config();

                        if ( empty( $this->events['purchase'] ) ) {
                                return;
                        }

                        $this->measurement_id = '' !== $this->measurement_id ? $this->measurement_id : $this->get_measurement_id();

                        if ( '' === $this->measurement_id ) {
                                return;
                        }

                        $order = wc_get_order( $order_id );

                        if ( ! $order instanceof \WC_Order ) {
                                return;
                        }

                        $payload = $this->build_purchase_payload( $order );

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

                        $json_payload = wp_json_encode( $payload );

                        ?>
<script>
if (typeof gtag === 'function') {
        gtag('event', 'purchase', <?php echo $json_payload; ?>);
}
</script>
                        <?php
                }

                private function get_measurement_id() {
                        $value = fluXtore_Settings::get( fluXtore_Google_Analytics_Settings::OPTION_MEASUREMENT_ID, '' );

                        return is_string( $value ) ? trim( $value ) : '';
                }

                private function get_events_config() {
                        return [
                                'page_view'      => $this->get_flag( fluXtore_Google_Analytics_Settings::OPTION_PAGE_VIEW, true ),
                                'begin_checkout' => $this->get_flag( fluXtore_Google_Analytics_Settings::OPTION_BEGIN_CHECKOUT, true ),
                                'add_payment_info' => $this->get_flag( fluXtore_Google_Analytics_Settings::OPTION_ADD_PAYMENT_INFO, true ),
                                'purchase'       => $this->get_flag( fluXtore_Google_Analytics_Settings::OPTION_PURCHASE, true ),
                        ];
                }

                private function build_config() {
                        $step = fluXtore_Tracking_Helper::get_step_context();

                        return [
                                'id'       => $this->measurement_id,
                                'events'   => $this->events,
                                'step'     => $step,
                                'currency' => fluXtore_Tracking_Helper::get_currency(),
                        ];
                }

                private function build_page_view_payload( $config ) {
                        $payload = [
                                'send_to' => $this->measurement_id,
                        ];

                        $step = isset( $config['step'] ) && is_array( $config['step'] ) ? $config['step'] : [];

                        if ( ! empty( $step['id'] ) ) {
                                $payload['step_id'] = (int) $step['id'];
                        }

                        if ( ! empty( $step['tag'] ) ) {
                                $payload['step_tag'] = $step['tag'];
                        }

                        return apply_filters( 'fluxtore_google_analytics_page_view_payload', $payload, $config );
                }

                private function build_begin_checkout_payload( $config ) {
                        $payload = [
                                'send_to' => $this->measurement_id,
                        ];

                        $step = isset( $config['step'] ) && is_array( $config['step'] ) ? $config['step'] : [];

                        if ( ! empty( $step['id'] ) ) {
                                $payload['step_id'] = (int) $step['id'];
                        }

                        if ( ! empty( $step['tag'] ) ) {
                                $payload['step_tag'] = $step['tag'];
                        }

                        if ( ! empty( $config['currency'] ) ) {
                                $payload['currency'] = $config['currency'];
                        }

                        return apply_filters( 'fluxtore_google_analytics_begin_checkout_payload', $payload, $config );
                }

                private function build_purchase_payload( \WC_Order $order ) {
                        $currency = $order->get_currency();
                        $value    = (float) $order->get_total();

                        $payload = [
                                'send_to'        => $this->measurement_id,
                                'transaction_id' => (string) $order->get_order_number(),
                                'value'          => $value,
                                'currency'       => $currency,
                        ];

                        $step = isset( $this->config['step'] ) && is_array( $this->config['step'] ) ? $this->config['step'] : fluXtore_Tracking_Helper::get_step_context();

                        if ( ! empty( $step['id'] ) ) {
                                $payload['step_id'] = (int) $step['id'];
                        }

                        if ( ! empty( $step['tag'] ) ) {
                                $payload['step_tag'] = $step['tag'];
                        }

                        $tax_total      = (float) $order->get_total_tax();
                        $shipping_total = (float) $order->get_total_shipping();

                        if ( $tax_total > 0 ) {
                                $payload['tax'] = $tax_total;
                        }

                        if ( $shipping_total > 0 ) {
                                $payload['shipping'] = $shipping_total;
                        }

                        $coupon_codes = $order->get_coupon_codes();

                        if ( ! empty( $coupon_codes ) ) {
                                $payload['coupon'] = implode( ',', $coupon_codes );
                        }

                        $items      = [];
                        $order_items = fluXtore_Tracking_Helper::get_order_items( $order );

                        foreach ( $order_items as $item ) {
                                $mapped = $this->map_order_item_to_ga_payload( $item );

                                if ( ! empty( $mapped ) ) {
                                        $items[] = $mapped;
                                }
                        }

                        if ( ! empty( $items ) ) {
                                $payload['items'] = $items;
                        }

                        return apply_filters( 'fluxtore_google_analytics_purchase_payload', $payload, $order );
                }

                private function map_order_item_to_ga_payload( $item ) {
                        $quantity = isset( $item['quantity'] ) ? (int) $item['quantity'] : 0;

                        if ( $quantity <= 0 ) {
                                $quantity = 1;
                        }

                        $unit_price = 0.0;

                        if ( isset( $item['unit_price'] ) ) {
                                $unit_price = (float) $item['unit_price'];
                        } elseif ( isset( $item['total'] ) && $quantity > 0 ) {
                                $unit_price = (float) $item['total'] / $quantity;
                        }

                        $product_id = isset( $item['product_id'] ) ? (string) $item['product_id'] : '';
                        $sku        = isset( $item['sku'] ) ? (string) $item['sku'] : '';
                        $identifier = $product_id;

                        if ( '' === $identifier && isset( $item['id'] ) ) {
                                $identifier = (string) $item['id'];
                        }

                        if ( '' === $identifier && '' !== $sku ) {
                                $identifier = $sku;
                        }

                        if ( '' === $identifier ) {
                                return [];
                        }

                        $ga_item = [
                                'item_id'  => $identifier,
                                'quantity' => $quantity,
                        ];

                        if ( '' !== $sku && $sku !== $identifier ) {
                                $ga_item['item_sku'] = $sku;
                        }

                        if ( ! empty( $item['name'] ) ) {
                                $ga_item['item_name'] = $item['name'];
                        }

                        if ( $unit_price > 0 ) {
                                $ga_item['price'] = $unit_price;
                        }

                        if ( ! empty( $item['variation_id'] ) ) {
                                $ga_item['item_variant'] = (string) $item['variation_id'];
                        }

                        return apply_filters( 'fluxtore_google_analytics_order_item_payload', $ga_item, $item );
                }

                private function get_flag( $option, $default = false ) {
                        $raw = fluXtore_Settings::get( $option, $default ? '1' : '0' );

                        if ( is_bool( $raw ) ) {
                                return $raw;
                        }

                        if ( is_numeric( $raw ) ) {
                                return (bool) intval( $raw );
                        }

                        if ( is_string( $raw ) ) {
                                $raw = trim( $raw );

                                if ( '' === $raw ) {
                                        return (bool) $default;
                                }

                                $filtered = filter_var( $raw, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE );

                                if ( null !== $filtered ) {
                                        return $filtered;
                                }
                        }

                        return (bool) $default;
                }
        }
}

fluXtore_Google_Analytics::init();
