<?php

namespace BWDK\Integrations\Digify\Routes;

use BWDK\Enums\BWDK_OrderStatus;
use BWDK\Integrations\Digify\Client;
use BWDK\Support\Constant;
use BWDK\Support\WooCompatibility;
use WC_Order_Item_Fee;
use WC_Order_Item_Shipping;
use WC_Session_Handler;
use WP_REST_Request;
use WP_REST_Response;
use WC_Order;


class CallbackRoute
{
    protected string $ns = 'bwdk/v1';

    protected string $route = '/digify/callback';

    public function register(): void
    {
/*        add_action('rest_api_init', function () {
            register_rest_route($this->ns, $this->route, [
                'methods' => 'GET',
                'callback' => [$this, 'handle'],
                'permission_callback' => '__return_true',

            ]);
        });*/


            add_rewrite_rule(
                '^bwdk-callback/?$',
                'index.php?__bwdk_callback=1',
                'top'
            );
        flush_rewrite_rules();


        add_filter('query_vars', function($vars) {
            $vars[] = '__bwdk_callback';
            return $vars;
        });

        add_action('template_redirect', function() {
            if ( get_query_var('__bwdk_callback') ) {

                $this->handle();
                exit;
            }
        });



    }


    public function handle( ): WP_REST_Response
    {
        $req=$_GET;
        $phone_number = (string)$req["phone_number"];
        $order_uuid = (string)$req["order_uuid"];
        $merchant_order_id = (int)$req["merchant_order_id"];
        $order = null;
        if ($merchant_order_id) {
            $order = wc_get_order($merchant_order_id);
        }


        if (!$order instanceof WC_Order && $order_uuid) {
            $orders = wc_get_orders([
                'limit' => 1,
                'meta_key' => \BWDK\Support\Constant::META_BWDK_UUID,
                'meta_value' => $order_uuid,
                'return' => 'objects',
            ]);

            $order = $orders ? reset($orders) : null;
        }


        if (!$order instanceof WC_Order) {
            return new WP_REST_Response([
                'ok' => false,
                'error' => 'order_not_found',
            ], 404);
        }

        if (!empty($order_uuid)) {
            $order->update_meta_data(\BWDK\Support\Constant::META_BWDK_UUID, $order_uuid);
        }

        if (!empty($phone_number)) {
            $current_phone = $order->get_billing_phone();


            if (empty($current_phone)) {
                $order->set_billing_phone($phone_number);
            } else {
                $order->set_billing_phone($phone_number);
            }
        }

        $client = new Client();
        $data = $client->orderGetStatus($order_uuid);

        $raw = $data['raw'] ?? [];


        if (json_last_error() !== JSON_ERROR_NONE || empty($raw)) {
            return new WP_REST_Response(['ok' => false, 'error' => 'invalid_api_response'], 502);
        }


        if (!empty($raw)) {
            $order->update_meta_data(\BWDK\Support\Constant::META_BWDK_JSON_CB, $raw);
        }

        $dest = $raw['destination_address'] ?? null;
        if ($dest) {
            $apply = $this->bwdk_apply_address_shipping_billing($order, $dest, []);

            if (!$apply['ok']) {
                error_log('Dest map failed: ' . $apply['error']);
            }
        }

        $ship = $raw['selected_shipping_method'] ?? null;
        if ($ship) {
            $this->bwdk_apply_shipping_method(
                $order,
                'digify_shipping:' . (string)$ship['id'],
                (string)($ship['name'] ?? ''),
                (float)($ship['cost'] ?? 0),
                [
                    'get_shipping_type_display' => $ship['get_shipping_type_display'] ?? null,
                    'cost' => $ship['cost'] ?? null,
                    'minimum_time_sending' => $ship['minimum_time_sending'] ?? null,
                    'maximum_time_sending' => $ship['maximum_time_sending'] ?? null,
                    'delivery_time_display' => $ship['delivery_time_display'] ?? null,
                    'delivery_time_range_display' => $ship['delivery_time_range_display'] ?? null,
                ],
                true,
                true
            );
        }

        $selected_packing = $raw['selected_packing'] ?? null;



        if ($selected_packing) {
            $this->bwdk_apply_packing($order,$selected_packing);
        }

        $user = $raw['user'] ?? null;

        if ($user) {
            $order->set_billing_first_name($user['first_name'] ?? null);
            $order->set_billing_last_name($user['last_name'] ?? null);
            $order->set_billing_phone($user['phone_number'] ?? null);

            $order->set_shipping_first_name($user['first_name'] ?? null);
            $order->set_shipping_last_name($user['last_name'] ?? null);
            $order->set_shipping_phone($user['phone_number'] ?? null);
        }

        $status = $raw['status'] ?? 2;



        $map = [
            7 => 'processing',
            3 => 'cancelled',
            2 => 'pending',
            8 => 'failed',
            6 => 'cancelled',
            9 => 'processing',
        ];

        if (!empty($status) && isset($map[$status])) {
            $order->set_status($map[$status]);
        }


        $options = get_option(Constant::BWDK_OPTION_NAME);

        $force_login=$options["force-login"]['status']??0;


        $order_received_url ="";

        if ($status==BWDK_OrderStatus::PENDING) {
            $order_received_url= $order->get_meta(Constant::META_BWDK_CB_URL);
        }


        if ($status==BWDK_OrderStatus::FAILED_TO_PAY) {
            $order->update_meta_data('_bwdk_error', 'پرداخت ناموفق بود');
            wc_setcookie( 'bwdk_error', "پرداخت ناموفق بود", time() + HOUR_IN_SECONDS );
            $order_received_url= $order->get_meta(Constant::META_BWDK_CB_URL);
        }

        if($status==BWDK_OrderStatus::PAID_BY_USER){


            if ($raw["total_paid_amount"]==$order->get_total()){
                $verify=(new Client())->verifyOrder($order,$order_uuid);
                if (isset($verify)&&$verify["status"]==BWDK_OrderStatus::VERIFIED_BY_MERCHANT){
                    $raw["status"] = BWDK_OrderStatus::VERIFIED_BY_MERCHANT;
                    $raw["status_display"] = BWDK_OrderStatus::label( BWDK_OrderStatus::VERIFIED_BY_MERCHANT);
                    $order->update_meta_data(\BWDK\Support\Constant::META_BWDK_JSON_CB, $raw);
                    $order_received_url= $order->get_checkout_order_received_url();
                }
            }
            wc()->cart->empty_cart();
        }


        if ($force_login && $status==BWDK_OrderStatus::PAID_BY_USER) {
            $order_received_url =get_page_link($options['thankyou-page']['id']) ;
            $order_received_url = add_query_arg( 'order', $order->get_id(), $order_received_url );
            $order_received_url = add_query_arg( 'key', $order->get_order_key(), $order_received_url );
            wc()->cart->empty_cart();
        }

        if ($status==BWDK_OrderStatus::VERIFIED_BY_MERCHANT) {
            $order_received_url= $order->get_meta(Constant::META_BWDK_CB_URL);
        }



        $order->save();
        wp_safe_redirect( $order_received_url );
        exit;
    }

    function bwdk_get_order_meta_dynamic( $order, string $meta_key, bool $single = true ) {


        if ( function_exists('wc_hpos_is_enabled') && wc_hpos_is_enabled() ) {
            return $order->get_meta( $meta_key, $single );
        } else {
            return get_post_meta( $order->get_id(), $meta_key, $single );
        }
    }

    public function bwdk_apply_address_shipping_billing(WC_Order $order, array $destination, array $opts = []): array
    {


        if (!$order instanceof WC_Order) {
            return ['ok' => false, 'error' => 'invalid_order', 'updated_fields' => []];
        }
        if (empty($destination) || !is_array($destination)) {
            return ['ok' => false, 'error' => 'invalid_destination', 'updated_fields' => []];
        }


        $country = $opts['country'] ?? 'IR';
        $billing_mode = $opts['billing_mode'] ?? 'always';
        $phone = isset($opts['phone']) ? (string)$opts['phone'] : '';
        $save_meta = array_key_exists('save_meta', $opts) ? (bool)$opts['save_meta'] : true;

        $clean = static function ($v) {
            return wc_clean(trim((string)$v));
        };


        $addr1 = $clean($destination['address'] ?? '');
        $building = $clean($destination['building_number'] ?? '');
        $unit = $clean($destination['unit'] ?? '');
        $district = $clean($destination['district_name'] ?? '');
        $city = $clean($destination['city_name'] ?? '');
        $stateName = $clean($destination['state_name'] ?? '');
        $postal = preg_replace('/\D+/', '', (string)($destination['postal_code'] ?? ''));
        $lat = $clean($destination['latitude'] ?? '');
        $lng = $clean($destination['longitude'] ?? '');
        $dkId = $clean($destination['digikala_id'] ?? '');


        $addr2Parts = array_filter([
            $district ?: null,
            $building ? "پلاک {$building}" : null,
            $unit ? "واحد {$unit}" : null,
        ]);
        $addr2 = $clean(implode('، ', $addr2Parts));


        $stateCode = $stateName;
        if (function_exists('WC') && WC()->countries) {
            $states = WC()->countries->get_states($country) ?: [];
            $found = array_search($stateName, $states, true);
            if ($found !== false) {
                $stateCode = $found;
            }
        }

        $updated = [];

        // ---------- Shipping ----------
        if ($addr1) {
            $order->set_shipping_address_1($addr1);
            $updated[] = 'shipping_address_1';
        }
        $order->set_shipping_address_2($addr2);
        $updated[] = 'shipping_address_2';
        if ($city) {
            $order->set_shipping_city($city);
            $updated[] = 'shipping_city';
        }
        if ($stateCode) {
            $order->set_shipping_state($stateCode);
            $updated[] = 'shipping_state';
        }
        if ($postal !== '') {
            $order->set_shipping_postcode($postal);
            $updated[] = 'shipping_postcode';
        }
        if ($country) {
            $order->set_shipping_country($country);
            $updated[] = 'shipping_country';
        }


        if ($phone !== '' && !$order->get_billing_phone()) {
            $order->set_billing_phone($phone);
            $updated[] = 'billing_phone';
            $updated[] = 'billing_phone';
        }

        // ---------- Billing ----------
        $should_fill_billing =
            ($billing_mode === 'always') ||
            ($billing_mode === 'if_empty' && !$order->get_billing_address_1());

        if ($should_fill_billing) {
            if ($addr1) {
                $order->set_billing_address_1($addr1);
                $updated[] = 'billing_address_1';
            }
            $order->set_billing_address_2($addr2);
            $updated[] = 'billing_address_2';
            if ($city) {
                $order->set_billing_city($city);
                $updated[] = 'billing_city';
            }
            if ($stateCode) {
                $order->set_billing_state($stateCode);
                $updated[] = 'billing_state';
            }
            if ($postal !== '') {
                $order->set_billing_postcode($postal);
                $updated[] = 'billing_postcode';
            }
            if ($country) {
                $order->set_billing_country($country);
                $updated[] = 'billing_country';
            }


            if ($phone !== '') {
                $order->set_billing_phone($phone);
                $updated[] = 'billing_phone';
            }
        }

        // ---------- Extra meta ----------
        if ($save_meta) {
            if ($dkId !== '') {
                $order->update_meta_data('_dest_digikala_id', $dkId);
                $updated[] = '_dest_digikala_id';
            }
            if ($district !== '') {
                $order->update_meta_data('_dest_district_name', $district);
                $updated[] = '_dest_district_name';
            }
            if ($lat !== '') {
                $order->update_meta_data('_dest_latitude', $lat);
                $updated[] = '_dest_latitude';
            }
            if ($lng !== '') {
                $order->update_meta_data('_dest_longitude', $lng);
                $updated[] = '_dest_longitude';
            }
        }

        return ['ok' => true, 'error' => null, 'updated_fields' => array_values(array_unique($updated))];
    }

    public function bwdk_apply_payment_method(WC_Order $order, string $method_id, string $method_title): array
    {
        if (!$order instanceof WC_Order) {
            return ['ok' => false, 'error' => 'invalid_order', 'updated_fields' => []];
        }
        if ($method_id === '' && $method_title === '') {
            return ['ok' => false, 'error' => 'no_payment_info', 'updated_fields' => []];
        }

        $updated = [];

        if ($method_id !== '') {
            $order->set_payment_method($method_id);
            $updated[] = '_payment_method';
        }
        if ($method_title !== '') {
            $order->set_payment_method_title($method_title);
            $updated[] = '_payment_method_title';
        }

        return ['ok' => true, 'error' => null, 'updated_fields' => $updated];
    }

    public function bwdk_apply_packing($order,$selected_packing)
    {

        $label=$selected_packing["name"]??"";
        $amount=$selected_packing['price']??0;
        foreach ($order->get_fees() as $packing) {

            if ("هزینه بسته بندی:". $label==$packing["name"]){
                return false;
            }

        }

        $item = new WC_Order_Item_Fee();
        $item->set_name( "هزینه بسته بندی:". $label );
        $item->set_total(WooCompatibility::convert_to_store_currency((float)$amount) );
        $order->add_item( $item );
        $order->calculate_totals( true );
        return true;
    }

    public function bwdk_apply_shipping_method(
        WC_Order $order,
        string   $method_id,
        string   $method_title,
        float    $cost = 0.0,
        array    $extras = [],
        bool     $also_save_on_order = false,
        bool     $recalculate_totals = true
    ): array
    {
        if (!$order instanceof WC_Order) {
            return ['ok' => false, 'error' => 'invalid_order', 'updated_fields' => []];
        }
        if ($method_id === '' && $method_title === '') {
            return ['ok' => false, 'error' => 'no_shipping_info', 'updated_fields' => []];
        }


        foreach ($order->get_items('shipping') as $item_id => $item) {
            $order->remove_item($item_id);
        }



        $shipping_item = new WC_Order_Item_Shipping();
        if ($method_id !== '') {
            $shipping_item->set_method_id($method_id);
        }
        if ($method_title !== '') {
            $shipping_item->set_method_title($method_title);
        }

        if (isset($extras['cost'])) {
            $cost = WooCompatibility::convert_to_store_currency((float)$extras['cost']);
        }
        $shipping_item->set_total((float)$cost);

        $meta_key_map = [
            'get_shipping_type_display' => '_ship_type_display',
            'cost' => '_ship_cost_api',
            'minimum_time_sending' => '_ship_min_days',
            'maximum_time_sending' => '_ship_max_days',
            'delivery_time_display' => '_ship_delivery_display',
            'delivery_time_range_display' => '_ship_delivery_range',
        ];

        $updated_meta_keys = [];


        foreach ($meta_key_map as $api_key => $meta_key) {
            if (!array_key_exists($api_key, $extras)) {
                continue;
            }
            $value = $extras[$api_key];


            if (is_array($value)) {
                $value = wp_json_encode($value, JSON_UNESCAPED_UNICODE);
            }


            if (is_string($value)) {
                $value = wc_clean($value);
            }

            $shipping_item->add_meta_data($meta_key, $value, true);
            $updated_meta_keys[] = $meta_key;

            if ($also_save_on_order) {
                $order->update_meta_data($meta_key, $value);
            }
        }

        $order->add_item($shipping_item);


        if ($recalculate_totals) {

            $order->calculate_totals(false);
        }

        return [
            'ok' => true,
            'error' => null,
            'updated_fields' => array_merge(
                ['shipping_method', 'shipping_method_title', 'shipping_cost'],
                $updated_meta_keys
            ),
        ];
    }

}
