<?php

class AmazonRefTag
{
    const FALLBACK_LOCATION = [
            'ashburn'   => 'ashburn',
            'chicago'   => 'ashburn',
            'sanjose'   => 'ashburn',
            'frankfurt' => 'ashburn',
            //'singapore' => 'ashburn',
            'vegas'     => 'turnkey',
            'turnkey'   => 'vegas',
        ];
    private $_location = null;
    private $_timeout = 3;
    private $_connectionTimeout = 1;
    private $_locationWiseUrl = array(
                                    'ashburn'   => array(
                                                        "keyword"=> array(
                                                                        "url" =>"https://192.168.31.100:9200/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedia&32!"
                                                                    ),
                                                        "shop" =>   array(
                                                                        "url" =>"https://192.168.26.133:9200/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedads@#4*"
                                                                    )
                                                    ),
                                    'chicago'   => array(
                                                        "keyword"=> array(
                                                                        "url" =>"https://172.16.28.90:9200/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedia&32!"
                                                                    ),
                                                        "shop" =>   array(
                                                                        "url" =>"https://172.16.17.7:9200/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedads@#4*"
                                                                    )
                                                    ),
                                    'sanjose'   => array(
                                                        "keyword"=> array(
                                                                        "url" =>"https://10.0.29.27:9200/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedia&32!"
                                                                    ),
                                                        "shop" =>   array(
                                                                        "url" =>"https://10.0.28.157:9200/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedads@#4*"
                                                                    )
                                                    ),
                                    'frankfurt' => array(
                                                        "keyword"=> array(
                                                                        "url" =>"https://10.9.16.40:9200/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedia&32!"
                                                                    ),
                                                        "shop" =>   array(
                                                                        "url" =>"https://10.9.31.170:9200/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedads@#4*"
                                                                    )
                                                    ),
                                    /*'singapore' => array(
                                                        "keyword"=> array(
                                                                        "url" =>"https://10.8.16.206:9200/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedia&32!"
                                                                    ),
                                                        "shop" =>   array(
                                                                        "url" =>"https://10.8.24.19:9200/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedads@#4*"
                                                                    )
                                                    ),*/
                                    'vegas'     => array(
                                                        "keyword"=> array(
                                                                        "url" =>"https://i5wbnxz6wptfvg24tbtcc2wv34.apigateway.us-sanjose-1.oci.customer-oci.com/v1/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedia&32!"
                                                                    ),
                                                        "shop" =>   array(
                                                                        "url" =>"https://hyj6egjkfb2l2no4d3lwytezu4.apigateway.us-sanjose-1.oci.customer-oci.com/v1/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedads@#4*"
                                                                    )
                                                    ),
                                    'turnkey'   => array(
                                                        "keyword"=> array(
                                                                        "url" =>"https://mfrbj5blwaxv3vztwcujpc3ofu.apigateway.us-ashburn-1.oci.customer-oci.com/v1/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedia&32!"
                                                                    ),
                                                        "shop" =>   array(
                                                                        "url" =>"https://pmr27esbybe2ydn4hdyfl2oc5m.apigateway.us-ashburn-1.oci.customer-oci.com/v1/",
                                                                        "username" => "admedia",
                                                                        "password" => "AdMedads@#4*"
                                                                    )
                                                    )
                                );

    public function __construct()
    {

    }

    private function _getServer(){
        /*$ip = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '';
        $map = [
		'ashburn'   => '/^192\.168\./',
		'cron-201' => '/^150\.136\.59\.155$/',
            'chicago'   => '/^172\.16\./',
            'sanjose'   => '/^10\.0\./',
            'frankfurt' => '/^10\.9\./',
            //'singapore' => '/^10\.8\./',
            'vegas'     => '/^(72\.219\.237\.|10\.10\.10\.)/',
            'turnkey'   => '/^(104\.129\.170\.|173\.198\.200\.)/',
        ];

        $location = 'ashburn';//default as ashburn if not match
        foreach ($map as $loc => $pattern) {
            if (preg_match($pattern, $ip)) {
                $location = $loc;
                break;
            }
        }
        if(isset( $_GET['debug'] ) && $_GET['debug'] == "reftag"){
            var_dump("server IP is $ip and location info is",$location);
        }*/

        $location = 'ashburn';//default as ashburn if not match
        return $location;

    }
    private function _curl($index,$query,$locationInfo){

        $url = $locationInfo['url']."$index/_search";
        $username = $locationInfo['username'];
        $password = $locationInfo['password'];

        $jsonData = json_encode($query);
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json'
        ]);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData);
        // ---------- Added by Scott to set a timeout for fallback --------
        // ---------- ADD THESE TWO FOR TIMEOUT ----------
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,$this->_connectionTimeout);  // max 1 seconds to connect
        curl_setopt($ch, CURLOPT_TIMEOUT, $this->_timeout); // max 3 seconds for the entire request
        $response = curl_exec($ch);
        
        // Capture HTTP status code and curl errors before closing
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curlError = curl_errno($ch) ? curl_error($ch) : null;
        $curlErrno = curl_errno($ch);
        
        if ($curlErrno) {
            if(isset( $_GET['debug'] ) && $_GET['debug'] == "reftag"){
                echo 'Curl error: ' . $curlError;
            }
        }
        if(isset( $_GET['debug'] ) && $_GET['debug'] == "reftag"){
            var_dump("curl info",curl_getinfo($ch));
        }
        curl_close($ch);
        
        // Return structured response with HTTP status, error info, and Elasticsearch data
        $result = [
            'status' => $httpCode,
            'error' => $curlError,
            'success' => ($httpCode >= 200 && $httpCode < 300 && !$curlErrno),
            'data' => null
        ];
        
        // Decode JSON response if we got one
        if ($response !== false && $response !== null) {
            $decoded = json_decode($response, true);
            if ($decoded !== null) {
                $result['data'] = $decoded;
            }
        }
        
        return $result;
    }

    // -------------------------------------------------------------------------------------
    // Added by Scott Hallett - 
    // The following method is a wrapper method/function that you will
    // use instead of _curl() in order to fallback to the fallback constant API endpoint
    // if the primary fails.
    private function tryHosts(string $index, array $query, array $locationInfo, string $type)
    {
        // Attempt primary (caller-provided locationInfo)
        $primaryResponse = $this->_curl($index, $query, $locationInfo);

        // Null safety check - ensure we got a valid response structure
        if (!is_array($primaryResponse)) {
            $primaryResponse = [
                'status' => 0,
                'error' => 'Invalid response from primary host',
                'success' => false,
                'data' => null
            ];
        }

        // Check if primary was successful
        if (isset($primaryResponse['success']) && $primaryResponse['success'] === true && 
            isset($primaryResponse['data']) && is_array($primaryResponse['data'])) {
            // SUCCESS ON PRIMARY - return Elasticsearch data format with metadata
            $result = $primaryResponse['data'];
            $result['used_host'] = 'primary';
            return $result;
        }

        // Build fallback locationInfo 
        $fallbackLocation = self::FALLBACK_LOCATION[$this->_location];
        if (!isset($this->_locationWiseUrl[$fallbackLocation][$type])) {
            // Fallback type missing - return error in Elasticsearch-compatible format
            return [
                'error' => [
                    'type' => 'fallback_config_error',
                    'reason' => "Fallback info missing for type '$type'"
                ],
                'used_host' => null
            ];
        }

        $fallbackInfo = $this->_locationWiseUrl[$fallbackLocation][$type];

        // Attempt fallback
        $fallbackResponse = $this->_curl($index, $query, $fallbackInfo);

        // Null safety check - ensure we got a valid response structure
        if (!is_array($fallbackResponse)) {
            $fallbackResponse = [
                'status' => 0,
                'error' => 'Invalid response from fallback host',
                'success' => false,
                'data' => null
            ];
        }

        // Check if fallback was successful
        if (isset($fallbackResponse['success']) && $fallbackResponse['success'] === true && 
            isset($fallbackResponse['data']) && is_array($fallbackResponse['data'])) {
            // SUCCESS ON FALLBACK - return Elasticsearch data format with metadata
            $result = $fallbackResponse['data'];
            $result['used_host'] = 'fallback';
            return $result;
        }

        // BOTH FAILED → return error in Elasticsearch-compatible format
        return [
            'error' => [
                'type' => 'both_hosts_failed',
                'reason' => "Primary and fallback both failed.",
                'primary_error' => isset($primaryResponse['error']) ? $primaryResponse['error'] : 'Unknown error',
                'fallback_error' => isset($fallbackResponse['error']) ? $fallbackResponse['error'] : 'Unknown error',
                "errorinfo"=> array("locationinfo"=>$locationInfo,"index"=>$index, "query" => $query)
            ],
            'used_host' => null,
        ];
    }
    // -------------------------------------------------------------------------------------

    public function getShopReftag($index,$sku){
        $this->_location = $this->_getServer();
        $locationInfo = $this->_locationWiseUrl[$this->_location]["shop"];
        $result = array();
        $result['status'] = true;    
        //get ref tag data
        if($sku == "GARBAGE"){
            $response = false;//go for random
        }else{
            $query = [
                '_source' => ['reftag',"cat_id","category"], // only return this field
                'size' => 1,
                'query' => [
                        'term' => [ // exact match
                        'sku' => $sku
                    ]
                ]
            ];
            // Commented out by Scott, to test the tryHosts(wrapper)
            //$response = $this->_curl($index,$query,$locationInfo);
            $response = $this->tryHosts($index,$query,$locationInfo, "shop");
            if(isset( $_GET['debug'] ) && $_GET['debug'] == "reftag"){
                var_dump("response=> ",$response);
            }
        }
        
        // Check for error response or valid hits
        if (is_array($response) && !isset($response['error']) && !empty($response['hits']['hits'])) {
            //found data for sku
            $result['reftag'] = $response['hits']['hits'][0]['_source']['reftag'];
            $result['cat_id'] = $response['hits']['hits'][0]['_source']['cat_id'];
            $result['category'] = $response['hits']['hits'][0]['_source']['category'];
        } else {
            $randNumber = rand(0,10000);
            $query = [
                '_source' => ['reftag',"cat_id","category"], // only return this field
                'size' => 1,
                "from"    => $randNumber,
                "sort"    => ["_doc"]
            ];
            // Commented out by Scott, to test the tryHosts(wrapper)
            //$response = $this->_curl($index,$query,$locationInfo);
            $response = $this->tryHosts($index,$query,$locationInfo, "shop");
            if(isset( $_GET['debug'] ) && $_GET['debug'] == "reftag"){
                var_dump("response=> ",$response);
            }
            // Check for error response before accessing hits
            if (is_array($response) && !isset($response['error']) && !empty($response['hits']['hits'])) {
                $result['reftag'] = $response['hits']['hits'][0]['_source']['reftag'];
                $result['cat_id'] = $response['hits']['hits'][0]['_source']['cat_id'];
                $result['category'] = $response['hits']['hits'][0]['_source']['category'];
            }
        }
        if(!isset($result['reftag'])){
            //means error occur
            $result['status'] = false;
            $result['error'] = $response;
            $result["errorinfo"]= array("locationinfo"=>$locationInfo,"index"=>$index, "query" => $query);
        }
        return json_encode($result);
    }
    /**
     * get shop reftag for xml  OR formultiple skus
     * we can ignore this for changes as we are not using same on xml side
     */
    public function getShopReftags($index,$skus){
        $this->_connectionTimeout = 0.5;
        $this->_timeout = 0.5;
        $this->_location = $this->_getServer();
        $locationInfo = $this->_locationWiseUrl[$this->_location]["shop"];
        $result = array();
        //get ref tag data
        $query = [
            '_source' => ['sku','reftag'], // only return this field
            'size' => count($skus),
            'query' => [
                    'terms' => [ // exact match
                    'sku' => $skus
                ]
            ]
        ];
        // Commented out by Scott, to test the tryHosts(wrapper)
        //$response = $this->_curl($index,$query,$locationInfo);
        $response = $this->tryHosts($index,$query,$locationInfo, "shop");
        if(isset( $_GET['debug'] ) && $_GET['debug'] == "reftag"){
            var_dump("response=> ",$response);
        }
        // Check for error response or valid hits
        if (is_array($response) && !isset($response['error']) && !empty($response['hits']['hits'])) {
            //found data for sku
            foreach($response['hits']['hits'] as $val){
                $result[$val['_source']['sku']] = $val['_source']['reftag'];
            }
            $result['random'] = $result[array_rand($result)];
        } else {
            $randNumber = rand(0,1000);
            $query = [
                '_source' => ['reftag'], // only return this field
                'size' => 1,
                "from"    => $randNumber,
                "sort"    => ["_doc"]
            ];
            // Commented out by Scott, to test the tryHosts(wrapper)
            //$response = $this->_curl($index,$query,$locationInfo);
            $response = $this->tryHosts($index,$query,$locationInfo, "shop");
            if(isset( $_GET['debug'] ) && $_GET['debug'] == "reftag"){
                var_dump("response=> ",$response);
            }
            // Check for error response before accessing hits
            if (is_array($response) && !isset($response['error']) && !empty($response['hits']['hits'])) {
                $result['random'] = $response['hits']['hits'][0]['_source']['reftag'];
            }
        }
        if(isset($response['error'])){
            //means error occur
            $result['status'] = false;
            $result['error'] = $response;
            $result["errorinfo"]= array("locationinfo"=>$locationInfo,"index"=>$index, "query" => $query);
        }
        return json_encode($result);
    }

    public function getLegacySearchKeyword($index, $device, $keyword = null)
    {
        $this->_location = $this->_getServer();
        $locationInfo = $this->_locationWiseUrl[$this->_location]["keyword"];
        $result = array();
        $result['status'] = true;
        // --- 1) Build keyword query (primary)
        if (!empty($keyword)) {
            $keywordQuery = [
                "_source" => ["dest_url", "cat_id", "category"],
                "size" => 1,
                "query" => [
                    "bool" => [
                        "must" => [
                            "match" => [
                                "kw" => $keyword
                            ]
                        ],
                        "filter" => [
                            "term" => [
                                "device" => $device
                            ]
                        ]
                    ]
                ]
            ];

            // Run keyword query first
            $response = $this->tryHosts($index, $keywordQuery, $locationInfo, "keyword");

            $hasResult = is_array($response) && !isset($response["error"]) && !empty($response["hits"]["hits"]);

            // If keyword result exists, return it
            if ($hasResult) {
                $result["refTag"] = isset($response["hits"]["hits"][0]["_source"]["dest_url"]) ?
                                    $response["hits"]["hits"][0]["_source"]["dest_url"] : null;
                $result["catId"] = isset($response['hits']['hits'][0]['_source']['cat_id']) ? $response['hits']['hits'][0]['_source']['cat_id'] : null;
                $result["category"] = isset($response['hits']['hits'][0]['_source']['category']) ? $response['hits']['hits'][0]['_source']['category'] : null;
                return json_encode($result);
            }

            // Otherwise fall through to random query below
        }

        // --- 2) Fallback: original random device query
        $randomQuery = [
            "_source" => ["dest_url", "cat_id", "category"],
            "size" => 1,
            "query" => [
                "function_score" => [
                    "query" => [
                        "match" => [
                            "device" => $device
                        ]
                    ],
                    "random_score" => new stdClass()
                ]
            ]
        ];

        $response = $this->tryHosts($index, $randomQuery, $locationInfo, "keyword");

        if (isset( $_GET['debug'] ) && $_GET['debug'] == "reftag") {
            var_dump("fallback response => ", $response);
        }

        if (is_array($response) && !isset($response["error"]) && !empty($response["hits"]["hits"])) {
            $result["refTag"] = isset($response["hits"]["hits"][0]["_source"]["dest_url"])
                                ? $response["hits"]["hits"][0]["_source"]["dest_url"]
                                : null;
            $result["catId"] = isset($response["hits"]["hits"][0]["_source"]["cat_id"])
                                ? $response["hits"]["hits"][0]["_source"]["cat_id"]
                                : null;
            $result["category"] = isset($response['hits']['hits'][0]['_source']['category']) ? $response['hits']['hits'][0]['_source']['category'] : null;
        } else {
            $result['status'] = false;
            $result['error'] = $response;
            $result["errorinfo"]= array("locationinfo"=>$locationInfo,"index"=>$index,"keywordquery" => $keywordQuery, "randomquery" => $randomQuery);
            $result["refTag"] = $result["catId"] = $result["category"] = null;
        }
        return json_encode($result);
    }
}
