<?php
require_once "../../system/lib/config.php";

use Firebase\JWT\JWT;

/**
 * 
 * Payment API cURL-Option
 * @author Anton
 *
 */
class Settle extends System {
    
    /**
     * 
     * param-data-provider
     * @var string
     */
    private $payload = NO_STRING;
    
    /**
     * 
     * api-param
     * @var string
     */
    private $signature;
    
    /**
     * 
     * api-param
     * @var string
     */
    private $pnum;
    
    /**
     * 
     * api-param
     * @var string
     */
    private $amount;
    
    /**
     * 
     * api-param
     * @var string
     */
    private $currency;
    
    /**
     * 
     * api-param
     * @var string
     */
    private $title;
    
    /**
     * 
     * api-param
     * @var string
     */
    private $successUrl;
    
    /**
     * 
     * api-param
     * @var string
     */
    private $returnUrl;
    
    /**
     * api-param
     * @var string
     */
    private $failedUrl;
    
    /**
     * api-param
     * @var string
     */
    private $language;
    
    /**
     * 
     * api-param
     * @var array
     */
    private $freeParams = [];
    
    /**
     * 
     * validation
     * @var array
     */
    private $invalid    = [];
    
    /**
     * 
     * request-method 
     * @var string
     */
    private $requestType;
    
    /**
     * 
     * header-data
     * @var string
     */
    private $contentType;
    
    /**
     * 
     * ip-address
     * @var string
     */
    private $ipAddress;
    
    public function __construct(){
        parent::__construct();
        header("Content-type: text/json");
        
        $this -> setParameter();
        $this -> validation();
    }
    
    private function setParameter(){ 
       $this -> contentType = $this -> getColumnData($_SERVER, "CONTENT_TYPE");
       $this -> requestType = $this -> getColumnData($_SERVER, "REQUEST_METHOD");
       $this -> ipAddress   = $this -> getColumnData($_SERVER, "REMOTE_ADDR");
       
       $this -> payload = file_get_contents("php://input");
       
       if($this -> checkJSONString($this -> payload)){
           $payObject = json_decode($this -> payload, true);
           
           $this -> pnum        = $this -> getColumnData($payObject, PARAM_P_NUM);
           $this -> currency    = $this -> getColumnData($payObject, PARAM_CURRENCY);
           $this -> signature   = $this -> getColumnData($payObject, PARAM_SIGNATURE);
           $this -> amount      = $this -> getColumnData($payObject, PARAM_AMOUNT);
           $this -> title       = $this -> getColumnData($payObject, PARAM_TITLE);
           $this -> language    = $this -> getColumnData($payObject, PARAM_LANGUAGE);
           $this -> successUrl  = $this -> getColumnData($payObject, PARAM_SUCCESS_URL);
           $this -> returnUrl   = $this -> getColumnData($payObject, PARAM_RETURN_URL);
           $this -> failedUrl   = $this -> getColumnData($payObject, PARAM_FAIL_URL);
           
           $freePs = $this -> getColumnData($payObject, "free_params");
           
           if($this -> isLoopData($freePs)){
               $this -> freeParams = array_merge($this -> freeParams, $freePs);
           }
       }
    }
    
    private function validation(){
        $accessArray = [
            "IP_Address" => $this -> getColumnData($_SERVER, "REMOTE_ADDR"),
            "Request_Method" => $this -> requestType,
            "Payload" => $this -> payload,
            "GETDATA" => json_encode($_GET),
            "POSTDATA" => json_encode($_POST),
            "Program_Code" => $this -> pnum,
            "Headers" => apache_request_headers()
        ];
        
        $this -> logDetails(print_r($accessArray, true));
        
        if(strcasecmp($this -> requestType, "POST") !== 0){
            $this -> invalid["DERR1"] = "Invalid Request Type [{$this -> requestType}]";
        }
        
        if($this -> contentType != "application/json"){
            $this -> invalid["DERR2"] = "Invalid Content Type [{$this -> contentType}]";
        }
                
        if($this -> checkJSONString($this -> payload)){
            if($this -> currency != NO_STRING){
                if(!$this -> checkCurrency(strtoupper($this -> currency)))
                    $this -> invalid["DERR3"] = "Invalid Currency [{$this -> currency}]";
            }else
                $this -> invalid["DERR4"] = "Currency is required";

            
            if($this -> amount != NO_STRING){
                if($this -> amount == NO_COUNT){
                    $this -> invalid["DERR5"] = "Amount cannot be 0";
                }
                
                if(!$this -> checkStringNumber($this -> amount)){
                    $this -> invalid["DERR6"] = "Invalid Inputted Amount.";
                }
            }else
                $this -> invalid["DERR7"] = "Amount is required";
            
            if($this -> language != NO_STRING){
                $languages = ["en", "ja", "tc", "sc", "id"];
                $this -> language = strtolower($this -> language);
                
                if(!in_array($this -> language, $languages)){
                    $this -> invalid["DERR8"] = "The Settlement Feature is not available to the language you've specified. [{$this -> language}]";
                }
            }else
                $this -> invalid["DERR9"] = "Language is required";            
            
            if($this -> pnum != NO_STRING){
                $apiSignature = $this -> getRowData($this -> getAPISignatureCommon($this -> pnum));
                
                if($this -> isLoopData($apiSignature)){
                    $userAccount = NO_STRING;
                    
                    if(!$this -> checkSettlementSignature(
                        $this -> pnum,
                        $this -> signature,
                        $userAccount)){
                            $this -> invalid["DERR10"] = "Invalid Settlement Signature";
                    }
                    
                    $wlistSettings = $this -> getColumnData($apiSignature, COLUMN_WHITELIST_SETTING);
                    
                    if($this -> checkJSONString($wlistSettings)){
                        $wlistSettings = json_decode($wlistSettings, true);
                                                
                        if($this -> getColumnData($wlistSettings, "allow_ip_in_payment")){
                            $ipAddresses = explode(",", $this -> getColumnData($apiSignature, "ip_address"));    
                            
                            if(!in_array($this -> ipAddress, $ipAddresses))
                                $this -> invalid["DERR11"] = "Invalid IP Address [{$this -> ipAddress}]";
                        }
                        
                        if(!$this -> getColumnData($wlistSettings, "allow_curl_in_payment")){
                            $this -> invalid["DERR12"] = "Authentication Denied for this Program Code.";
                        }
                    }
                    
                }else
                    $this -> invalid["DERR13"] = "Invalid Program Code";
            }else
                $this -> invalid["DERR14"] = "Program Code is required";
        }else
            $this -> invalid["DERR15"] = "Invalid Payload Format";
        
        if($this -> isLoopData($this -> invalid)){
            $this -> logDetails("Settlement Request Denied: ".print_r($this -> invalid, true));
            header("HTTP/1.1 401 Unauthenticated");
            
            $errorTraces = [];
            foreach($this -> invalid as $errcode => $description){
                $errorTraces[] = [
                    "errcode" => $errcode,
                    "description" => $description
                ];
            }
            
            die(json_encode($errorTraces));
        }
    }
    
    /**
     *
     * @param string $content
     */
    private function logDetails($content){
        $timestamp = date("Y-m-d H:i:s");
        
        $logDir = SITE_ROOT."api/Logs/settlement/curl";
        
        if(!@file_exists($logDir))
            mkdir($logDir, 0777, true);
            
        $logFile = "{$logDir}/Log_".date("Y-m-d").".log";
        error_log("[{$timestamp}]\n\n{$content}\n\n", VAL_INT_3, $logFile);
    }
    
    /**
     * 
     * Validation-Passed Invocation
     * 
     */
    public function listen(){
        
        
        $this -> accessModifyCommon('INSERT_LOG_POST', array(
            $this -> ipAddress,
            $this -> pnum,
            $this -> getColumnData($_SERVER, "HTTP_REFERER"),
            "[SERVER_TO_SERVER]{$this -> payload}"));
        
        $middlewareSettings = $this -> getSettingConfiguration("middleware_conf");
        $settlementSettings = $this -> getSettingConfiguration("payment_api_conf");
        
        $jwtPayload = [
            "purpose" => "PaymentAPI",
            "created" => date("Y-m-d H:i:s"),
            "expiration" => date("Y-m-d H:i:s", strtotime($settlementSettings -> link_duration)),
            "data" => base64_encode(json_encode([
                PARAM_P_NUM => $this -> pnum,
                PARAM_SIGNATURE => $this -> signature,
                PARAM_TITLE => $this -> title,
                PARAM_LANGUAGE => $this -> language,
                PARAM_AMOUNT => $this -> amount,
                PARAM_CURRENCY => $this -> currency,
                PARAM_SUCCESS_URL => $this -> successUrl,
                PARAM_FAIL_URL => $this -> failedUrl,
                PARAM_RETURN_URL => $this -> returnUrl,
                PARAM_SETTLEMENT_ORIGIN => "server_to_server",
                PARAM_SETTLEMENT_FREE_PARAMS => $this -> freeParams
            ]))
        ];
                
        $jwtToken = JWT::encode($jwtPayload, 
            $middlewareSettings -> token_secretkey, 
            $middlewareSettings -> algorithm); 
        
        $baseUrl = SITE_PROTOCOL."://".SITE_DOMAIN_FULL;
        
        $tokenUrl = "{$baseUrl}/{$this -> language}/middleware?token={$jwtToken}";
        $this -> logDetails($tokenUrl);
        
        echo $tokenUrl;
    }
}

$settle = new Settle();
$settle -> listen();