<?php

namespace Modules\PrintSuppliers\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Modules\PrintSuppliers\Models\Order;
use Modules\PrintSuppliers\Models\Shipper;
use Modules\PrintSuppliers\Models\OrderMeta;

class TeezilyController extends Controller
{
    private $apiUrl;
    private $credential;
    protected $printPositons;

    public function __construct()
    {
        $this->credential = $this->getCredential('printerval', 'teezily');
        $this->apiUrl = Config::get('print-suppliers::connection.teezily.api_url', 'http://bops.xiaosache.com/zspic');

        $this->printPositons = [
            "TSRN_U" => ["front", "back"],
            "TSRN_W" => ["front", "back"],
            "TSVN_U" => ["front", "back"],
            "TSVN_W" => ["front", "back"],
            "TSLS_U" => ["front", "back"],
            "SWTR_U" => ["front", "back"],
            "HOOD_U" => ["front", "back"],
            "TSRN_K" => ["front", "back"],
            "HOOD_K" => ["front", "back"],
            "TKTP_U" => ["front", "back"],
            "TKTP_W" => ["front", "back"],
            "BODY_B" => ["front", "back"],
            "BODYLS_B" => ["front", "back"],
            "OTSRN_U" => ["front", "back"],
            "OTSRN_W" => ["front", "back"],
            "OTSVN_U" => ["front", "back"],
            "OTSVN_W" => ["front", "back"],
            "OTSLS_U" => ["front", "back"],
            "OSWTR_U" => ["front", "back"],
            "OHOOD_U" => ["front", "back"],
            "PTSRN_U" => ["front", "back"],
            "PSWTR_U" => ["front", "back"],
            "PHOOD_U" => ["front", "back"],
            "TOTE_U" => ["front", "back"],
            "MUG_U" => ["front"],
            "BMUG_U" => ["front"],
            "BTTMUG_U" => ["front"],
            "LMUG_U" => ["front"],
            "RMUG_U" => ["front"],
            "TTMUG_U" => ["front"],
            "DMAT3-2_U" => ["front"],
            "FLEEB_U" => ["front"],
            "FMASK_U" => ["front"],
            "IP5C_U" => ["front"],
            "IP5SC_U" => ["front"],
            "IP6C_U" => ["front"],
            "IP6PC_U" => ["front"],
            "SGS5C_U" => ["front"],
            "SGS6C_U" => ["front"],
            "MIPICA2-1_U" => ["front"],
            "SAPICA1-1_U" => ["front"],
            "NECKL_R" => ["front"],
            "NECKL_S" => ["front"],
            "ORCE_H" => ["front"],
            "ORCE_R" => ["front"],
        ];
    }

    public function internalCallApi(Request $request)
    {
        $endPoint = $request->input('end_point');
        $method = $request->input('method', 'GET');
        $params = $request->input('params', []);
        
        return $this->triggerSyncRequest($this->apiUrl . '/' . $endPoint, $method, $params, [
            'Authorization: Bearer ' . $this->credential[1],
            'Content-Type: application/json'
        ]);
    }

    public function buildProducts()
    {
        $responseProducts = $this->triggerSyncRequest($this->apiUrl . '/v2/catalog/products?limit=100', 'GET', [], [
            'Authorization: Bearer ' . $this->credential[1],
            'Content-Type: application/json'
        ]);

        $products = [];
        if (isset($responseProducts['results'])) {
            foreach ($responseProducts['results'] as $product) {

                $products[] = [
                    'id' => $product['id'],
                    'reference' => $product['reference'],
                    'name' => $product['name'],
                    'image' => $product['image']
                ];

                if(isset($product['variants'])) {
                    $variants = [];
                    foreach ($product['variants'] as $variant) {
                        $variants[] = [
                            'id' => $variant['id'],
                            'reference' => $variant['reference'],
                            'name' => $variant['name'],
                            'color' => $variant['color'],
                            'size' => $variant['size'],
                            'product_id' => $product['id']
                        ];
                    }
                    DB::table('teezily_variants')->insert($variants);
                }
            }
        }

        DB::table('teezily_products')->insert($products);
    }

    public function getProducts()
    {
        $products = DB::table('teezily_products')->get()->toArray();

        $products = array_map(function($product) {

            $product->print_positions = ['front'];
            $product->name = ucwords($product->name);

            if (isset($this->printPositons[$product->reference])) {
                $product->print_positions = $this->printPositons[$product->reference];
            }

            return $product;

        }, $products);

        return $products;
    }

    public function getVariants(Request $request)
    {
        $productId = $request->input('product_id');

        $variants = DB::table('teezily_variants')->where('product_id', $productId)->get();

        $colors = [];
        $sizes = [];

        foreach ($variants as $variant) {
            $colors[$variant->color] = ucwords($variant->color);
            $sizes[$variant->size] = ucwords($variant->size);
        }

        $colors = array_values($colors);
        sort($colors);

        $sizes = array_values($sizes);
        sort($sizes);

        return [
            'variants' => $variants,
            'colors' => $colors,
            'sizes' => $sizes
        ];
    }

    public function webhook(Request $request)
    {
        $webhookPayload = $request->all();
        $retVal['status'] = 'fail';

        $statusMapping = [
            "ongoing" => "ISSUED",
            "done" => "READY_TO_SHIP",
            // "DELIVERING" "FINISHED",
        ];

        if (isset($webhookPayload['event']['action'], $webhookPayload['event']['object_id'])) {

            $newStatus = null;
            $action = $webhookPayload['event']['action'];
            $objectId = $webhookPayload['event']['object_id'];

            if ($action == 'order_status_updated')
            {
                $dataState = $webhookPayload['data']['state'] ?? null;
                if ($dataState && isset($statusMapping[$dataState])) {
                    $newStatus = $statusMapping[$dataState];
                }
            } else if ($action == 'tracking_added') 
            {
                $newStatus = 'DELIVERING';
            }

            $teezilyOrder = $this->triggerSyncRequest($this->apiUrl . '/v2/orders/' . $objectId, 'GET', [], [
                'Authorization: Bearer ' . $this->credential[1],
                'Content-Type: application/json'
            ]);

            if (isset($teezilyOrder['external_reference'])) {

                $sysOrderCode = explode('_', $teezilyOrder['external_reference'])[1];

                $originOrder = Order::query()
                    ->where('code', '=', $sysOrderCode)
                    ->whereNotIn('status', ['CANCELED', 'REQUEST_RETURN', 'RETURNED', 'FINISHED'])
                    ->where('payment_status', '=', 'PAID')
                    ->orderBy('id', 'DESC')
                    ->first();

                if ($originOrder) {

                    $this->_updateOrder($originOrder, $teezilyOrder, $newStatus);
    
                    $retVal['status'] = 'successful';
                    $retVal['mapped_status'] = $newStatus;
    
                } else {
                    $retVal['status'] = 'fail';
                    $retVal['message'] = 'Order Not Found.';
                }

            } else {
                $retVal['status'] = 'fail';
                $retVal['message'] = 'Teezily external_reference Not Found.';
            }

        } else {
            $retVal['status'] = 'fail';
            $retVal['message'] = 'Empty merchize ex ID & DATA.';
        }

        return response()->json($retVal, 200, [], JSON_NUMERIC_CHECK);

    }

    protected function _updateOrder($order, $teezilyOrder, $newStatus = null)
    {
        // update status and tracking code
        $dataUpdate = [];

        if ($newStatus) {
            $dataUpdate['status'] = $newStatus;        
        }

        // get tracking data
        if (isset($teezilyOrder['trackings'])) {
            $shipments = $this->updateShipments($teezilyOrder['trackings'], $order);
            if (!empty($shipments )) {
                $dataUpdate['shipments'] = $shipments;
            }
        }

        if (!empty($dataUpdate)) {
            $this->_sendUpdateOrder($order->id, $dataUpdate, [ "Referal: Webhook" ]);
        }
    }

    protected function _sendUpdateOrder($orderId, $dataUpdate, $headers = []) {
        $updateUrl = Config::get('sa.api_url') . '/api/update-order/' . $orderId;
        array_push($headers, 'Content-Type:application/json');
        return $this->triggerSyncRequest($updateUrl, 'POST', $dataUpdate, $headers);
    }

    protected function updateShipments($trackingData, $order)
    {
        $checkShipments = [];
        $shipments = [];

        foreach ($trackingData as $shipment)
        {
            $tempShipment = [];
            if (!empty($shipment['carrier'])) 
            {
                $shipper = Shipper::firstOrCreate([
                    'name' => $shipment['carrier']
                ], 
                [
                    'name' => $shipment['carrier'], 
                    'meta_data' => 'Created by Webhook'
                ]);

                $tempShipment['id'] = $shipper->id;
                $tempShipment['code'] = $shipment['number'];

                OrderMeta::updateOrCreate([ 'order_id' => $order->id, 'key' => 'shipment' ], [ 'value' => $shipper->id ]);

                if (!empty($shipment['url'])) {
                    $tempShipment['url'] = $shipment['url'];
                }

                $existShipment = $tempShipment['id'] . '-' . $tempShipment['code'];
                if (!in_array($existShipment, $checkShipments)) {
                    array_push($shipments, $tempShipment);
                    array_push($checkShipments, $existShipment);
                }
            }

        }

        if (!empty($shipments)) {
            OrderMeta::updateOrCreate([ 'order_id' => $order->id, 'key' => 'shipment_data' ], [ 'value' => json_encode($shipments) ]);
        }

        return $shipments;
    }
    
}
