<?php

namespace PortalPeople\netsuite\components;

use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
use PortalPeople\netsuite\NetSuiteClient;

/**
 * NetSuite Component with OAuth 2.0 JWT Authentication
 * 
 * This component provides easy access to NetSuite API functionality in Yii2 applications
 * 
 * @package PortalPeople\netsuite\components
 */
class NetSuite extends Component
{
    /**
     * @var string NetSuite account ID
     */
    public $accountId;
    
    /**
     * @var string Client ID from NetSuite integration record
     */
    public $clientId;
    
    /**
     * @var string Client secret from NetSuite integration record
     */
    public $clientSecret;
    
    /**
     * @var string Certificate ID (Key ID) from NetSuite
     */
    public $certificateId;
    
    /**
     * @var string Path to private key file for JWT signing
     */
    public $privateKeyPath;
    
    /**
     * @var string NetSuite user internal ID for impersonation
     */
    public $userId;
    
    /**
     * @var string NetSuite REST API base URL (optional, will be auto-generated if not provided)
     */
    public $baseUrl;
    
    /**
     * @var NetSuiteClient NetSuite client instance
     */
    private $_client;
    
    /**
     * @inheritdoc
     */
    public function init()
    {
        parent::init();
        
        if (empty($this->accountId)) {
            throw new InvalidConfigException('NetSuite account ID must be configured');
        }
        
        if (empty($this->clientId)) {
            throw new InvalidConfigException('NetSuite client ID must be configured');
        }
        
        if (empty($this->clientSecret)) {
            throw new InvalidConfigException('NetSuite client secret must be configured');
        }
        
        if (empty($this->certificateId)) {
            throw new InvalidConfigException('NetSuite certificate ID (Key ID) must be configured');
        }
        
        if (empty($this->privateKeyPath)) {
            throw new InvalidConfigException('Private key path must be configured');
        }
        
        if (empty($this->userId)) {
            throw new InvalidConfigException('NetSuite user ID must be configured');
        }
        
        // Resolve private key path relative to module directory if not absolute
        if (!$this->isAbsolutePath($this->privateKeyPath)) {
            $this->privateKeyPath = \Yii::getAlias('@app') . '/' . ltrim($this->privateKeyPath, '/');
        }
    }
    
    /**
     * Check if path is absolute
     * 
     * @param string $path
     * @return bool
     */
    private function isAbsolutePath($path)
    {
        return (PHP_OS_FAMILY === 'Windows') 
            ? preg_match('/^[a-zA-Z]:[\\\\\/]/', $path)
            : strpos($path, '/') === 0;
    }
    
    /**
     * Get NetSuite client instance
     * 
     * @return NetSuiteClient
     */
    public function getClient()
    {
        if ($this->_client === null) {
            $this->_client = new NetSuiteClient([
                'accountId' => $this->accountId,
                'clientId' => $this->clientId,
                'clientSecret' => $this->clientSecret,
                'certificateId' => $this->certificateId,
                'privateKeyPath' => $this->privateKeyPath,
                'userId' => $this->userId,
                'baseUrl' => $this->baseUrl
            ]);
        }
        
        return $this->_client;
    }
    
    /**
     * Create a new record in NetSuite
     * 
     * @param string $recordType The type of record to create (e.g., 'customer', 'item', 'salesorder')
     * @param array $data Record data
     * @return array Response data
     */
    public function createRecord($recordType, $data)
    {
        return $this->getClient()->post("/record/v1/{$recordType}", $data);
    }
    
    /**
     * Get a record from NetSuite by ID
     * 
     * @param string $recordType The type of record to retrieve
     * @param int $recordId The internal ID of the record
     * @return array Response data
     */
    public function getRecord($recordType, $recordId)
    {
        return $this->getClient()->get("/record/v1/{$recordType}/{$recordId}");
    }
    
    /**
     * Update a record in NetSuite
     * 
     * @param string $recordType The type of record to update
     * @param int $recordId The internal ID of the record
     * @param array $data Updated record data
     * @return array Response data
     */
    public function updateRecord($recordType, $recordId, $data)
    {
        return $this->getClient()->patch("/record/v1/{$recordType}/{$recordId}", $data);
    }
    
    /**
     * Delete a record from NetSuite
     * 
     * @param string $recordType The type of record to delete
     * @param int $recordId The internal ID of the record
     * @return array Response data
     */
    public function deleteRecord($recordType, $recordId)
    {
        return $this->getClient()->delete("/record/v1/{$recordType}/{$recordId}");
    }
    
    /**
     * Search for records in NetSuite
     * 
     * @param string $recordType The type of record to search
     * @param array $criteria Search criteria
     * @param array $options Search options (limit, offset, etc.)
     * @return array Response data
     */
    public function searchRecords($recordType, $criteria = [], $options = [])
    {
        $params = [];
        
        if (!empty($criteria)) {
            $params['q'] = json_encode($criteria);
        }
        
        if (!empty($options['limit'])) {
            $params['limit'] = $options['limit'];
        }
        
        if (!empty($options['offset'])) {
            $params['offset'] = $options['offset'];
        }
        
        return $this->getClient()->get("/query/v1/{$recordType}", $params);
    }
    
    /**
     * Execute a SuiteQL query
     * 
     * @param string $query SuiteQL query string
     * @param array $options Query options (limit, offset, etc.)
     * @return array Response data
     */
    public function executeQuery($query, $options = [])
    {
        $params = ['q' => $query];
        
        if (!empty($options['limit'])) {
            $params['limit'] = $options['limit'];
        }
        
        if (!empty($options['offset'])) {
            $params['offset'] = $options['offset'];
        }
        
        return $this->getClient()->get('/query/v1/suiteql', $params);
    }
    
    /**
     * Get record metadata
     * 
     * @param string $recordType The type of record
     * @return array Response data
     */
    public function getRecordMetadata($recordType)
    {
        return $this->getClient()->get("/record/v1/{$recordType}/metadata");
    }

    /**
     * Get metadata catalog for a record type
     *
     * @param string $recordType The record type to retrieve the catalog for (default: 'salesorder')
     * @return array Response data
     */
    public function getMetadataCatalog($recordType = 'salesorder')
    {
        return $this->getClient()->get("/record/v1/metadata-catalog/{$recordType}");
    }

    
    /**
     * Test the connection to NetSuite
     * 
     * @return bool True if connection is successful
     */
    public function testConnection()
    {
        try {
            $this->getClient()->get('/record/v1/account/1');
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }


    public static function GetSendOrderfromNetsuite($id) {
        $array = [];
        $array[] = (\common\components\NetSuiteApi::get('https://' . Yii::$app->params['netsuite']['account_id'] . '.suitetalk.api.netsuite.com/services/rest/record/v1/salesorder/' . $id .'/item/1'))->content;
        $array[] = (\common\components\NetSuiteApi::get('https://' . Yii::$app->params['netsuite']['account_id'] . '.suitetalk.api.netsuite.com/services/rest/record/v1/salesorder/' . $id .'/item/2'))->content;
        $array[] = (\common\components\NetSuiteApi::get('https://' . Yii::$app->params['netsuite']['account_id'] . '.suitetalk.api.netsuite.com/services/rest/record/v1/salesorder/' . $id .'/item/3'))->content;
        return json_encode($array);
    }
    public static function SendOrderToNetsuite($id) {
        $cart = \backend\models\Cartsbe::find()->where(['id' => $id])->one();
        
        // Check if order was already sent to NetSuite
        if (!empty($cart->netsuiteid)) {
            $ns = json_decode($cart->netsuiteid, true);
            if (!empty($ns)) {
                Yii::warning("Order {$cart->id} already exists in NetSuite: " . json_encode($ns));
                return (object)[
                    'status' => 200,
                    'content' => json_encode(['message' => 'Order already exists in NetSuite', 'netsuite_id' => $ns]),
                    'already_exists' => true
                ];
            }
        }
        
        // Get customer IDs mapping from configuration
        $customerIds = Yii::$app->params['netsuite']['customerids'] ?? [];
        
        // Determine cart source (default to 'default' if not specified)
        $cartSource = 'default';
        
        // Look up customer ID for this source, fallback to 24435 if not found
        $customerId = 24435;
        foreach ($customerIds as $mapping) {
            if (isset($mapping['source']) && $mapping['source'] === $cartSource && !empty($mapping['customerid'])) {
                $customerId = (int)$mapping['customerid'];
                break;
            }
        }

        $netsuite = new \stdClass();
       // $netsuite->recordtype = 'salesorder';
        $netsuite->entity = new \stdClass();
        $netsuite->entity->id = $customerId;
        $netsuite->externalId = $cart->id . time(); //'/AB';
        $netsuite->email = $cart->email;
        $netsuite->total = 0 + $cart->total;
        $netsuite->source = 'NGauge Commerce';
        $netsuite->tranDate = Date('c', strtotime('now')); //dateTime
        $netsuite->customForm = new \stdClass();
        $netsuite->customForm->id = 100;
        $netsuite->customFieldList = new \stdClass();
        $netsuite->currency = new \stdClass();
        $netsuite->currency->id = 1;
        
        $netsuite->message = $cart->message; // string;
        $netsuite->balance = $cart->amountout;
        $netsuite->otherRefNum = $cart->orderref.' '.substr($cart->contact, 0,35); //dateTime
        $netsuite->billingAddress = [
            'addressee' => $cart->fulladdresses['billing']->contact,
            'addr1' => $cart->fulladdresses['billing']->address1,
            'addr2' => $cart->fulladdresses['billing']->address2,
            'city' => substr($cart->fulladdresses['billing']->town, 0 , 50),
            'state' => substr($cart->fulladdresses['billing']->county, 0, 30),
            'country' => 'GB',
            'zip' => $cart->fulladdresses['billing']->postcode,
        ];
        $netsuite->shippingAddress = [
            'addressee' => $cart->fulladdresses['shipping']->contact,
            'addr1' => $cart->fulladdresses['shipping']->address1,
            'addr2' => $cart->fulladdresses['shipping']->address2,
            'city' => substr($cart->fulladdresses['shipping']->town, 0, 50),
            'state' => substr($cart->fulladdresses['shipping']->county,0 ,30),
            'country' => 'GB',
            'zip' => $cart->fulladdresses['shipping']->postcode,
            // 'addrPhone' => $cart->fulladdresses['shipping']->telephone, //No Perms
         ];
        $items = [];
        foreach ($cart->cartlines as $line) {
            $nsdata = $line->product->data->netsuite ?? null;
            $item = new \stdClass();
            $item->externalId = $line->id;
            $item->item = new \stdClass();
            $item->item->id = intval($nsdata->erpid);
            $item->item->name = $line->product_name;
            
            // Fix undefined variables
            $extraDesc = $line->product_description ?? '';
            $erpqty = $nsdata->erp_qty ? $nsdata->erp_qty : 1;
            $requested_date = $cart->requested_date ?? 'now';
            
            $item->description = trim($line->product_name . ' ' . $line->product_description . ' ' . $extraDesc);
            $item->quantity = $line->qty * $erpqty;
            $pricePer = $line->price / $erpqty;
            $pricevat = $pricePer / (1 + (20 / 100)); // Fix VAT calculation
            $item->rate = $pricevat; // Set rate to price excluding VAT
            $item->requestedDate = date('c', strtotime('now')); // Add missing semicolon
            $item->expectedShipDate = date('c', strtotime($requested_date));
            !empty($nsdata->unit) ? $item->units = $nsdata->unit : false;
            $item->custcolweb_qty_sold = $item->quantity;
            $item->custcolweb_description = $item->description;
            $item->custcol10 = floatval($line->cost);
            $item->custcol_poRate = floatval($line->cost);
            $item->custcol_po_rate = floatval($line->cost);
            $item->custcol_po_vendor = new \stdClass();
            $item->custcol_po_vendor->id = $nsdata->supplierid ?? null;
            $netsuite->custbody_exp_ship_date_so = Date('c', strtotime($line->requested_date));
            $items[] = $item;
            /*** DISCOUNTS */
            if($line->disc > 0){
                $item = new \stdClass();
                $item->externalId = $line->id;
                $item->item = new \stdClass();
                $item->item->id = 1592; // AHS Discount Item ID
                //$item->item->name = $line->product_name;                
                // Fix undefined variables
                $extraDesc = $line->product_description ?? '';
                $erpqty = $nsdata->erp_qty ? $nsdata->erp_qty : 1;
                $requested_date = $cart->requested_date ?? 'now';
                
                $item->description = trim($line->product_name . ' ' . $line->product_description . ' ' . $extraDesc);
                $item->quantity = 1;
                $discvat = $line->disc / (1 + (20 / 100));
                $item->rate = 0 - $discvat; // Set rate to discount amount excluding VAT;                
                $item->requestedDate = date('c', strtotime('now')); // Add missing semicolon
                $item->expectedShipDate = date('c', strtotime($requested_date));
                $item->custcolweb_qty_sold = 1;
                $item->custcolweb_description = 'TRUST10 Discount || ' . $line->product_name;
                $item->custcol10 = floatval(0);
                $item->custcol_poRate = floatval(0);
                $item->custcol_po_rate = floatval(0);
                $item->custcol_po_vendor = new \stdClass();
                $item->custcol_po_vendor->id = 16336; // AHS Discount Vendor ID
                $netsuite->custbody_exp_ship_date_so = Date('c', strtotime($line->requested_date));
                $items[] = $item;
            }
        }
        //$netsuite->custbody_ahs_order_source = 'NGauge Commerce';

        $netsuite->item = new \stdClass();
        $netsuite->item->items = $items;

        $netsuite->memo = 'TEL:' . $cart->fulladdresses['shipping']->telephone . '    Email:' . $cart->email . '    MSG:' . $cart->message;
        
        try {
            $response = \common\components\NetSuiteApi::post('https://' . Yii::$app->params['netsuite']['account_id'] . '.suitetalk.api.netsuite.com/services/rest/record/v1/salesOrder', get_object_vars($netsuite));
        } catch (\Exception $e) {
            Yii::error("NetSuite API request failed for cart {$cart->id}: " . $e->getMessage());
            return (object)[
                'statusCode' => 400,
                'status' => 400,
                'content' => $e->getMessage(),
                'error' => true
            ];
        }
        
        // Handle response - HttpClient returns statusCode property
        $statusCode = $response->statusCode ?? $response->status ?? 0;
        
        if (!empty($response->isOk) || ((int)$statusCode >= 200 && (int)$statusCode < 300)) {
            $header = $response->getHeaders();
            $locationArray = explode('/', $header['location']);
            $id = $locationArray[array_key_last($locationArray)];
            if(!empty($id)){
                $cart->data->netsuite->deliveryid = $id;
                $cart->data->netsuite->last_sync_attempt = date('Y-m-d H:i:s');
                $cart->save(false);
                return (object)[
                    'statusCode' => 200,
                    'status' => 200,
                    'content' => $response->content,
                    'isOk' => true
                ];
            }
            // Save NetSuite ID to cart on success
            if (!empty($response->content)) {
                $content = is_string($response->content) ? json_decode($response->content, true) : $response->content;
                if (is_array($content) && !empty($content['id'])) {
                    $netsuiteData = [
                        'id' => $id,
                        'externalId' => $netsuite->externalId,
                        'created_at' => date('Y-m-d H:i:s')
                    ];
                    $cart->save(false);
                    Yii::info("Order {$cart->id} successfully sent to NetSuite. NetSuite ID: {$id}");
                    
                    // Return successful response
                    return (object)[
                        'statusCode' => 200,
                        'status' => 200,
                        'content' => $response->content,
                        'isOk' => true
                    ];
                }
            }
            // Success but no ID in response
            Yii::warning("Order {$cart->id} sent to NetSuite but no ID in response");
            return (object)[
                'statusCode' => 200,
                'status' => 200,
                'content' => $response->content,
                'isOk' => true
            ];
        }
        
        // Handle errors
        $errorContent = is_string($response->content) ? $response->content : json_encode($response->content);
        
        // Check if it's a "already exists" error
        if (strpos($errorContent, 'already exists') !== false) {
            Yii::warning("Order {$cart->id} already exists in NetSuite. ExternalId: {$netsuite->externalId}");
            return (object)[
                'statusCode' => 200,
                'status' => 200,
                'content' => json_encode(['message' => 'Order already exists in NetSuite', 'external_id' => $netsuite->externalId]),
                'already_exists' => true
            ];
        }
        
        Yii::error("NetSuite API Error for cart {$cart->id}: " . $errorContent);
        return $response;
    }

    public static function Adddeposit($id, $netsuiteid, $amount, $type)
    {
        $setting = Settings::findOne(['is_default' => 1]);
        $state = $setting->state;
        $model = Cartsbe::findOne(['id' => $id]);
		$ns = json_decode($model->netsuiteid, 1);

        $payment = $model->payment;
        $memo = '';
        if ($payment->paymentmethod == 'Card - CreditCard') {
            $memo = 'Card Payment ref: ' . $payment->paymentref . ' Card Shield: ' . $payment->cardno;
        } elseif ($payment->paymentmethod == 'Paypal') {
            $memo = 'Paypal Payment ref: ' . $payment->paymentref;
        }

        $deposit = new \stdClass();
        $deposit->externalId = $model->payment->id . '/' . $type;
        $deposit->customer = new \stdClass();
        $deposit->customer->id = Yii::$app->params['netsuite'][$state]['accountid'];
        $deposit->salesOrder = new \stdClass();
        $deposit->salesOrder->id = $netsuiteid;
        $deposit->paymentMethod = new \stdClass();
        $deposit->paymentMethod->id = $payment->paymentmethod == 'Card - CreditCard' ? 7 : ($payment->paymentmethod == 'Paypal' ? 10 : null);
        $deposit->payment = $amount;
        if (!empty($memo)) {
            $deposit->memo = $memo;
        }

        $response = \common\components\NetSuiteApi::post(
            'https://4465021.suitetalk.api.netsuite.com/services/rest/record/v1/customerDeposit',
            get_object_vars($deposit)
        );

        if (!empty($response->error) || (isset($response->status) && (int)$response->status >= 400)) {
            return ['status' => 100, 'cart_nsid' => null, 'message' => $response->content ?? 'NetSuite error'];
        }

        $paymentId = null;
        if (!empty($response->content)) {
            $content = is_string($response->content) ? json_decode($response->content, true) : $response->content;
            if (is_array($content) && !empty($content['id'])) {
                $paymentId = $content['id'];
            }
        }

        if ($paymentId !== null) {
            $payment->updateAttributes(['netsuiteid', $paymentId]);
        }

        return ['status' => 200, 'cart_nsid' => $model->netsuiteid, 'payment_id' => $paymentId, 'message' => 'Saved'];
    }


}