<?php
namespace App\Library;
use App\Core\Service\Logger;
use App\Service\Api;
use App\Config\Main;

class Shopify  
{   
    private $api = null;
    private $headers;
    private $store_name;    
    private $api_key;
    private $secret_key;
    private $access_token;
    private $api_version = '2025-10';
    private $credentials;
    private $credentials_base64;

    public function __construct(Array $settings) {
        $this->api = new Api();
        $this->headers = [];
        $this->api_version = Main::getShopifyApiVersion();
        $this->store_name = !empty($settings['api_url']) ? trim($settings['api_url']) : '';
        $this->api_key = !empty($settings['shopify_api_key']) ? trim($settings['shopify_api_key']) : '';
        $this->secret_key = !empty($settings['shopify_api_secret_key']) ? trim($settings['shopify_api_secret_key']) : '';
        $this->access_token = !empty($settings['shopify_access_token']) ? trim($settings['shopify_access_token']) : '';
        if(!empty($this->api_key) && !empty($this->access_token)) {
            $this->credentials = $this->api_key.':'.$this->access_token;
            $this->credentials_base64 = base64_encode($this->api_key.':'.$this->access_token);
            $this->headers = [
                "Content-Type" => "application/json",
                "Authorization" => "Basic ".$this->credentials_base64
            ];
        }
    }
    
    function verifyWebhook($data, $hmac_header, $secret) {
		$calculated_hmac = base64_encode(hash_hmac('sha256', $data, $secret, true));
		return hash_equals($hmac_header, $calculated_hmac);
	}

    private function getURL($for) {
        if($for == 'get_customer') {
            return "https://" . $this->store_name . ".myshopify.com/admin/api/". $this->api_version ."/customers/search.json";            
        } else if($for == 'add_update_customer') {
            return "https://" . $this->store_name . ".myshopify.com/admin/api/". $this->api_version ."/customers.json"; 
        } else if($for == 'create_order') {
            return "https://" . $this->store_name . ".myshopify.com/admin/api/". $this->api_version ."/orders.json";
        } else if($for == 'get_product') {
            return "https://". $this->credentials ."@" . $this->store_name . ".myshopify.com/admin/api/". $this->api_version ."/products.json";
        }
        return NULL;
    }

    private function checkConfiguration() {
        try {
            if(empty($this->api_version) || empty($this->store_name) || empty($this->api_key) || 
            empty($this->secret_key) || empty($this->access_token)) {
                throw new \Exception("Shopify configuration is incomplete. Provide all required settings.(API version, Store Name, API Key, Secret Key and Access Token)");
            }
            return true;
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return false;
        }
    }

    public function getCustomer($mobile_no) {
        try {
            if(!$this->checkConfiguration()) {
                throw new \Exception("getCustomer::Shopify configuration is incomplete. Provide all required settings.(API version, Store Name, API Key, Secret Key and Access Token)");
            }
            $url = $this->getURL('get_customer');
            if(empty($url)) {
                throw new \Exception("API URL not found to create customer on Shopify");
            }
            if(empty($url)) {
                throw new \Exception("Request headers not ");
            }
            $url = $url."?query=phone:" . urlencode($mobile_no);
            $callrs = $this->api->call($url, 'GET', $this->headers, '');
            if(empty($callrs['status'])) {
                throw new \Exception($callrs['error']);
            }
            $response = json_decode($callrs['data'], true);
            $ret_data = [
                "status"=>true, 
                "url"=>$url,
                "headers"=>json_encode($this->headers),
                "request_method"=>"GET",
                "api_request"  => NULL,
                "api_response" => $callrs['data'],
                "order_status" => 'ERROR',
                "data"=>NULL
            ];
            if(!empty($response)) {
                if(!empty($response['customers']) && is_array($response['customers'])) {
                    $ret_data['data'] = $response['customers'][0]['id'];
                    $ret_data['order_status'] = 'SUCCESS';
                }
            }
            return $ret_data;
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    public function addUpdateCustomer($order, $shopify_customer_id) {
        try {
            if(!$this->checkConfiguration()) {
                throw new \Exception("getCustomer::Shopify configuration is incomplete. Provide all required settings.(API version, Store Name, API Key, Secret Key and Access Token)");
            }
            $url = $this->getURL('add_update_customer');
            if(empty($url)) {
                throw new \Exception("API URL not found to create customer on Shopify");
            }
            if(!empty($shopify_customer_id)) {
                $url = str_replace("customers.json", "customers/".$shopify_customer_id.".json", $url);
            }            
            $post_data = [
                "customer" => [
                    "email" => !empty($order['customer_detail']['email_id']) ? $order['customer_detail']['email_id'] : '',
                    "phone" => "+91".trim($order['customer_detail']['mobile_number']),
                    "first_name" => $order['customer_detail']['customer_name'],
                    "addresses" => [
                        [
                            "address1" => $order['customer_address_detail']['address'],
                            "city" => $order['customer_address_detail']['address_city_name'],
                            "province" => $order['customer_address_detail']['address_state_name'],
                            "phone" => trim($order['customer_address_detail']['address_mobile']) ? "+91".trim($order['customer_address_detail']['address_mobile']):'',
                            "zip" => $order['customer_address_detail']['address_pincode'],
                            "country" => "India",
                        ]
                    ],
                    "currency" => "INR"
                ]
            ];
            if(!empty($shopify_customer_id)) {
                $post_data['customer']['id'] = $shopify_customer_id;
                unset($post_data['customer']['email_id']);
                unset($post_data['customer']['phone']);
            }
            $callrs = $this->api->call($url, 'POST', $this->headers, json_encode($post_data));
            if(empty($callrs['status'])) {
                if(empty($shopify_customer_id)) {
                    throw new \Exception($callrs['error']);
                }
                $response = "";
            } else {
                $response = json_decode($callrs['data'], true);
                
                if(empty($response)) {
                    throw new \Exception("No response from Shopify add/update customer API");
                }
                $shopify_customer_id = !empty($response['customer']['id']) ? $response['customer']['id'] : 0;
                if(empty($shopify_customer_id) && empty($response['customer'])) {
                    throw new \Exception("Shopify API failed to add/update customer");
                }
            }
            $ret_data = [
                "status"=>true, 
                "url"=>$url,
                "headers"=>json_encode($this->headers),
                "request_method"=>"POST",
                "api_request"  => json_encode($post_data, JSON_NUMERIC_CHECK),
                "api_response" => $response,
                "order_status" => 'SUCCESS',
                "data"=>!empty($shopify_customer_id)?$shopify_customer_id:0
            ];
            return $ret_data;
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }
    
    public function createOrder($data) {
        try {
            if(!$this->checkConfiguration()) {
                throw new \Exception("createOrder::Shopify configuration is incomplete. Provide all required settings.(API version, Store Name, API Key, Secret Key and Access Token)");
            }
            $url = $this->getURL('create_order');
            $callrs = $this->api->call($url, 'POST', $this->headers, json_encode($data, JSON_NUMERIC_CHECK));
            if(empty($callrs['status'])) {
                throw new \Exception($callrs['error']);
            }
            if(empty($callrs['data'])){
                throw new \Exception("Failed to create order on Shopify");
            } else {
                $ret_data = [
                    "status"=>true, 
                    "url"=>$url,
                    "headers"=>json_encode($this->headers),
                    "request_method"=>"POST",
                    "api_request"  => json_encode($data, JSON_NUMERIC_CHECK),
                    "api_response" => $callrs['data'],
                    "order_status" => 'ERROR',
                    "data"=>[]
                ];
                if($callrs['http_status'] == 201) {
                    $resp = json_decode($callrs['data'], true);
                    if(!empty($resp['order'])) {
                        $ret_data['order_status'] = 'SUCCESS';
                        $ret_data['data']['shopify_id'] = !empty($resp['order']['id']) ? $resp['order']['id'] : NULL;
                        $ret_data['data']['shopify_number'] = !empty($resp['order']['order_number']) ? $resp['order']['order_number'] : NULL;
                        $ret_data['data']['created_at'] = !empty($resp['order']['created_at']) ? $resp['order']['created_at'] : NULL;
                    }
                }
                return $ret_data;
            }
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    public function getProductIdByTitle($title) {
        try {
            if(!$this->checkConfiguration()) {
                throw new \Exception("getProductIdByTitle::Shopify configuration is incomplete. Provide all required settings.(API version, Store Name, API Key, Secret Key and Access Token)");
            }
            $url = $this->getURL('get_product');
            if(empty($url)) {
                throw new \Exception("API URL not found to get product from Shopify");
            }
            $url .= "?title=".urlencode($title);
            $products = [];
            do {
                $callrs = $this->api->call($url, 'GET', $this->headers, '');
                if(empty($callrs['status'])) {
                    throw new \Exception($callrs['error']);
                }
                $response = json_decode($callrs['data'], true);
                if(!empty($response)) {
                    $products = array_merge($products, $response['products']);
                }
                if (isset($callrs['reqinfo']['link']) && preg_match('/rel="next"/', $callrs['reqinfo']['link'])) {
					preg_match('/<(.*?)>/', $callrs['reqinfo']['link'], $matches);
					$url = $matches[1];
				} else {
					break;
				}
            } while(true);
            $productId = 0;
            $variantId = 0;
            $imageUrl  = NULL;
            if(!empty($products)) {
                foreach ($products as $product) {
                    if (trim($product['title']) === $title) {
                        $productId = $product['id'];
                        foreach ($product['images'] as $image) {
                            if (!empty($image['src'])) {
                                $imageUrl = $image['src'];
                                break;
                            }
                        }
                        foreach ($product['variants'] as $variant) {
                            $variantId = $variant['id'];
                            break;
                        }
                        if(!empty($variantId)) {
                            break;
                        }
                    }
                } 
            }
            return ["status"=>true, 'product_id' => $productId, 'variant_id' => $variantId, 'img_src' => $imageUrl];
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    public function prepareOrderData($order, $item, $shopify_customer_id) {
        try {
            $data = [
                'order'=>[
                    'tags' => 'ALLOWED',
                    'currency' => 'INR',
                    'order_number' => $order['customer_order_id'],
                    'total_discounts' => round($order['additional_discount']),
                    'total_tax' => $order['tax_amt'],
                    'customer' => [], 
                    'billing_address' => [],
                    'shipping_address' => [],
                    'line_items' => [],
                    'financial_status'=>[],
                ]
            ];
            $data['order']['customer']['id'] = $shopify_customer_id;
            $line_items = [];
            foreach ($item as $itemKey => $val) {
                if (empty($val['variant_id'])) {
                    $product_id = $this->getProductIdByTitle($val['item_name']);
                    if (!empty($product_id['variant_id'])) {
                        $line_items[$itemKey]['variant_id'] = $product_id['variantId'];
                    }
                } else {
                    $line_items[$itemKey]['variant_id'] = $val['variant_id'];
                }
                $line_items[$itemKey]['price'] = $val['rate'];
                $line_items[$itemKey]['quantity'] = $val['qty'];
                $line_items[$itemKey]['title'] = $val['item_name'];
                $line_items[$itemKey]['total_discount'] = $val['discount_amount'];
                $line_items[$itemKey]['tax_lines'] = [
                    [
                        'title' => "tax",
                        'price' => $val['tax_amount'],
                        'rate' => ($val['tax_percentage'] / 100)
                    ]
                ];
            }
            $data['order']['financial_status'] = (empty($order['payment_confirm_id'])) ? 'pending' : 'paid';
			if (isset($order['is_paid']) && $order['is_paid'] == 1) {
				$data['order']['financial_status'] =  'paid';
			}
			$data['order']['line_items'] = $line_items;
            $name = trim($order['customer_detail']['customer_name']);
            $name_arr = explode(" ", trim($order['customer_detail']['customer_name']));
            $last_name = trim(str_replace($name_arr[0],"",$name));
            $data['order']['shipping_address'] = [
                "first_name" => $name_arr[0],
                "last_name" => !empty($last_name)? $last_name : '.',
                "address1" => $order['customer_address_detail']['address'],
                "city" => $order['customer_address_detail']['address_city_name'],
                "province" => $order['customer_address_detail']['address_state_name'],
                "phone" => $order['customer_detail']['mobile_number'],
                "zip" => $order['customer_address_detail']['address_pincode'],
                "name" => $name,
                "country" => "India",
            ];
            $data['order']['billing_address'] = $data['order']['shipping_address'];
            if (empty($order['same_as_shipping']) && !empty($order['customer_billing_address'])) {
				$data['order']['billing_address'] = [
					"first_name" => $name_arr[0],
					"last_name" => !empty($last_name)? $last_name : '.',
					"address1" => $order['customer_address_detail']['address'],
					"city" => $order['customer_address_detail']['address_city_name'],
					"province" => $order['customer_address_detail']['address_state_name'],
					"phone" => $order['customer_detail']['mobile_number'],
					"zip" => $order['customer_address_detail']['address_pincode'],
					"name" => $name,
					"country" => "India",
                ];
			}
            $transactions = [];
            if ($order['advance_payment'] > 0) {
				$transactions[] = [
                    'kind' => 'sale', // or 'authorization' if you're capturing payment later
                    'status' => 'success', // can be 'pending', 'failure', etc.
                    'amount' => sprintf("%.2f", $order['advance_payment']), // Amount of the payment
                    'gateway' => 'Manual', // payment gateway if applicable
                    'payment_terms' => [
                        'payment_due' => date('Y-m-d', strtotime('+30 days')),
                        'payment_terms' => 'Net 30'
                    ]
                ];
			}
            if ($data['order']['financial_status'] == 'paid') {

				if ($order['partial_payment'] > 0) {
					$data['order']['tags'] = "ALLOWED,Partial payment Done";
					$amount = $order['partial_payment'];
					if ((int)($order['partial_payment'] + $order['advance_payment']) >=  (int)($order['gross_amt'] + $order['tax_amt'] - $order['additional_discount'])) {
						$data['order']['financial_status'] = 'paid';
					} else {
						$data['order']['financial_status'] = 'pending';
					}
				} else {
					$data['order']['tags'] = "ALLOWED,Payment Done";
					$amount = $order['gross_amt'];
					$data['order']['financial_status'] = 'paid';
				}
				
				$transactions[]  = [
                    'kind' => 'sale', // or 'authorization' if you're capturing payment later
                    'status' => 'success', // can be 'pending', 'failure', etc.
                    'amount' => sprintf("%.2f", $amount), // Amount of the payment
                    'gateway' => 'razorpay', // payment gateway if applicable
                    'payment_terms' => [
                        'payment_due' => date('Y-m-d', strtotime('+30 days')),
                        'payment_terms' => 'Net 30'
                    ]
                ];
			} else {
				$data['order']['financial_status'] = 'pending';
				if (floatval($order["net_amt"]) == 0) {
					$data['order']['tags'] = "ALLOWED,Payment Done";
					$data['order']['financial_status'] = 'paid';
				}
			}
			if (isset($order['is_paid']) && $order['is_paid'] == 1) {
				$data['order']['financial_status'] = 'paid';
				$data['order']['tags'] = "ALLOWED,Payment Done";
			}
            if (!empty($transactions)) {
				$data['order']['transactions'] = $transactions;
			}
            return ["status"=>true, "data"=>$data];
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }
}