<?php

namespace Modules\PrintSuppliers\Controllers;

use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Config;
use Modules\PrintSuppliers\Models\Order;
use Modules\PrintSuppliers\Models\Shipper;
use Modules\PrintSuppliers\Models\OrderMeta;
use Carbon\Carbon;
use Modules\PrintSuppliers\Models\OrderItem;
// use GuzzleHttp\Client;

class BondreController extends Controller
{
    private $apiUrl;
    private $storeNo;

    public function __construct()
    {
        $this->apiUrl = Config::get('print-suppliers::connection.bondre.api_url', '');
        $bondreAccounts = Config::get('print-suppliers::connection.bondre.accounts', []);
        if ($bondreAccounts) {
            foreach ($bondreAccounts as $account) {
                if (isset($account['default']) && $account['default']) {
                    $this->storeNo = $account['store_no'];
                    break;
                }
            }
        } else {
            $this->storeNo = null;
        }
    }

    public function autoFulfill(Request $request)
    {
        $responseData = [
            'status' => self::STATUS_FAIL,
            'msg' => 'order_id is required!'
        ];

        $orderId = $request->input('order_id');

        if ($orderId && $request->has('matching_skus')) {

            try {

                $order = $this->findOrderDetail($orderId);
                $order['resource_id'] = null;

                if ($order && (!isset($order['resource_id']) || !$order['resource_id'])) {
                    $orderSchema = $this->getFulfillOrderSchema($order, $request->input('matching_skus'));
                    if (isset($_GET['debug'])) {
                        dd($orderSchema);
                    }

                    if ($orderSchema) {
                        $fulfillResponse = $this->fulfill($order, $orderSchema);                        
                        if ($fulfillResponse['status'] !== false) {
                            $responseData['status'] = self::STATUS_SUCCESSFUL;
                            $itemIds = array_column($orderSchema, 'id');
                            OrderItem::query()->whereIn('id', $itemIds)
                                ->update([
                                    'printing_code' => 'bondre',
                                    'print_provider' => 'BONDRE',
                                ]);

                            // update resource_id
                            $resourceId = $this->storeNo . '-' . $order['code'];
                            $objectOrder = Order::query()->find($order['id']);
                            $objectOrder->resource_id = $resourceId;
                            $objectOrder->save();
                            $responseData['msg'] = 'Fulfill thành công!';
                        } else {
                            DB::table('log')->insert([
                                'actor_email' => 'system',
                                'target_id' => $order['id'],
                                'target_type' => 'ORDER',
                                'event_type' => 'BONDRE_AUTO_FULFILL_FAIL',
                                'data' => json_encode($fulfillResponse),
                                'created_at' => date('Y-m-d H:i:s')
                            ]);
                        }
                    } else {
                        $responseData['msg'] = 'Thông tin sku nhà in không hợp lệ';
                    }
                
                } else {
                    $msg = 'Không tìm thấy chi tiết đơn Printerval hoặc đơn đã được fulfill, kiểm tra resource_id trong đơn hàng!';
                    if (isset($order['resource_id']) && $order['resource_id']) {
                        $msg = 'Đơn fullfill trùng lặp!';
                    } elseif (!$order) {
                        $msg = 'Không tìm thấy chi tiết đơn Printerval';
                    }

                    $responseData = [
                        'status' => self::STATUS_FAIL,
                        'msg' => $msg
                    ];
                }

            } catch (Exception $ex) {
                $errorMsg = 'Error on line '. $ex->getLine().' in '.$ex->getFile() .': '.$ex->getMessage();
                $responseData = [
                    'status' => self::STATUS_FAIL,
                    'msg' => $errorMsg
                ];
            }
        }

        return $responseData;
    }

    protected function getFulfillOrderSchema($orderDetail, $matchingSkus)
    {
        $fullname = $orderDetail['customer']['full_name'];
        $phone = $orderDetail['customer']['phone'];
        $email = $orderDetail['customer']['email'];

        if (isset($orderDetail['attributes']['customer_info'])) {
            $fullname = $orderDetail['attributes']['customer_info']['full_name'];
            $phone = $orderDetail['attributes']['customer_info']['phone'];
            $email = $orderDetail['attributes']['customer_info']['email'];
        }

        if (isset($orderDetail['attributes']['gift_info']['name']) && $orderDetail['attributes']['gift_info']['name']) {
            $fullname = $orderDetail['attributes']['gift_info']['name'];
            $phone = $orderDetail['attributes']['gift_info']['phone'];
        }

        $schema = [
            'storeNo' => $this->storeNo,
            'orderNo' => $orderDetail['code'],
            'receiverName' => $fullname,
            'address' => $orderDetail['delivery_address'],
            'city' => $orderDetail['city_name'],
            'province' => $orderDetail['city_name'],
            'country' => !empty($orderDetail['country']) ? $orderDetail['country']['nicename'] : '',
            'zipCode'  => $orderDetail['zip_code'],
            'phone' => $phone,
            'email' => $email,
        ];

        $items = [];
        if (!empty($orderDetail['items'])) {
            foreach ($orderDetail['items'] as $item) {

                $artworks = [];
                $skuCheck = false;
                foreach ($matchingSkus as $sku) {
                    if (!empty($sku['order_item_id']) && $sku['order_item_id'] == $item['id'] && !empty($sku['sku'])) {
                        $order['sku'] = $sku['sku'];
                        $artworks = $sku['artworks'] ?? [];
                        $skuCheck = true;
                    }
                }

                if (!$skuCheck) {
                    return false;
                }

                $order = $schema;

                if (count($artworks)) {
                    $order['designLink'] = '';
                    if (isset($artworks['front']['url'])) {
                        $order['designLink'] = $artworks['front']['url'];
                    }
                    if (isset($artworks['back']['url'])) {
                        $order['designLink2'] = $artworks['back']['url'];
                    }
                } else {
                    $design = DB::table('design')
                        ->join('product_n_design', 'design.id', '=', 'product_n_design.design_id')
                        ->where('product_n_design.product_id', $item['product_id'])
                        ->where('product_n_design.is_primary', 1)
                        ->select('design.image_url')
                        ->first();
                    $configs = !empty($item['configurations']) ? json_decode($item['configurations'], true) : [];
                    if (!empty($configs['print_location']) && $configs['print_location'] == 'back') {
                        $order['designLink2'] = $design->image_url;
                        $order['designLink'] = '';
                    } else {
                        $order['designLink'] = $design->image_url;
                    }
                }
                
                $order['mockupLink'] = $item['image_url'];
                $order['quantity'] = $item['quantity'];
                $order['sku'] = $item['sku'];
                $order['id'] = $item['id'];
                $order['mark'] = $item['variants'];
                $variants = $this->getVariants($item);
                if (!empty($variants['Size'])) {
                    $order['size'] = $variants['Size'];
                }
                if (!empty($variants['Color'])) {
                    $order['color'] = $variants['Color'];
                }
                if (!empty($variants['Material'])) {
                    $order['color'] = $variants['Material'];
                }
                $callbackUrl = route('bondre.webhook');
                $order['callbackUrl'] = $callbackUrl;
                $items[] = $order;
            }
        }
        
        return $items;
  
    }

    private function getVariants($item) {
        $variants = explode(',', $item['variants']);
        $items = [];
        foreach ($variants as $variant) {
            $option = explode(':', $variant);
            if (empty($option[0]) || empty($option[1])) {
                continue;
            }
            $items[trim($option[0])] = trim($option[1]);
        }
        return $items;
    }

    protected function fulfill($order, $orderSchema)
    {

        if (empty($orderSchema)) {
            return false;
        }
        $result = [];
        $check = true;
        foreach ($orderSchema as $item) {
            if (!empty($item['id'])) {
                unset($item['id']);
            }
            $header = [
                'Content-Type: application/json'
            ];
            $response = $this->triggerSyncRequest($this->apiUrl . '/open/order/info/create', 'POST', $item, $header);
            if (!empty($response) && $response['code'] == 200) {
                $result[] = [
                    'item_sku' => $item['sku'],
                    'result' => true
                ];
            } else {
                $result[] = [
                    'item_sku' => $item['sku'],
                    'result' => false,
                    'response' => json_encode($response)
                ];
                $check = false;
                break;
            }
        }
        $this->logFulfill([
            'order_id' => $order['id'],
            'data' => $orderSchema
        ]);

        return [
            'status' => $check,
            'items' => $result
        ];
    }

    protected function logFulfill($logData)
    {
        DB::table('log')->insert([
            'actor_email' => 'system',
            'target_id' => $logData['order_id'],
            'target_type' => 'ORDER',
            'event_type' => 'BONDRE_AUTO_FULFILL',
            'data' => json_encode($logData['data']),
            'created_at' => date('Y-m-d H:i:s')
        ]);
    }

    public function webhook(Request $request) {
        $retval = [
            'status' => 'fail',
        ];
        DB::table('log')->insert([
            'actor_email' => 'system',
            'target_id' => $request->get('orderNo', '-1'),
            'target_type' => 'ORDER',
            'event_type' => 'BONDRE_AUTO_FULFILL_WEBHOOK',
            'data' => json_encode($request->all()),
            'created_at' => date('Y-m-d H:i:s')
        ]);
        if ($request->has('orderNo')) {
            $orderNo = $request->input('orderNo');
            $order = Order::query()->where('code', $orderNo)->first();
            if ($order) {
                if (!empty($request['trackingNo']) && !empty($request['courier'])) {
                    $trackingInfo = [
                        'tracking_number' => $request['trackingNo'],
                        'carrier' => $request['courier'],
                        'tracking_url' => !empty($request['trackingUrl']) ? $request['trackingUrl'] : null
                    ];
                    $this->updateTracking($order, $trackingInfo);
                    Order::query()->where('id', $order->id)->update(['status' => 'DELIVERING']);
                }

                $retval['status'] = 'success';
            } else {
                $retval['msg'] = 'order not found!';
            }
        } else {
            $retval['msg'] = 'orderNo is required!';
        }
        return $retval;
    }

    private function updateTracking($order, $trackingInfo)
    {
        $shipments = [];
        $shipmentKey = 'shipment';

        $shipper = null;
        if (!empty($trackingInfo['carrier'])) {
            $shipper = Shipper::firstOrCreate(['name' => $trackingInfo['carrier']], ['name' => $trackingInfo['carrier'], 'meta_data' => 'Created by Webhook']);
        }

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

            $shipment['id'] = $shipper->id;

            if (!empty($trackingInfo['tracking_number'])) {
                $shipment['code'] = $trackingInfo['tracking_number'];
            } 

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

        return $shipments;
    }

    public function readExcelFile($filePath)
    {
        $data = [];
        try {
            $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($filePath);
            $worksheet = $spreadsheet->getActiveSheet();
            $highestRow = $worksheet->getHighestRow();
            $highestColumn = $worksheet->getHighestColumn();
            $highestColumnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestColumn);

            for ($row = 1; $row <= $highestRow; $row++) {
                $rowData = [];
                for ($col = 1; $col <= $highestColumnIndex; $col++) {
                    $cellValue = $worksheet->getCellByColumnAndRow($col, $row)->getValue();
                    $rowData[] = $cellValue;
                }
                $data[] = $rowData;
            }
        } catch (\PhpOffice\PhpSpreadsheet\Reader\Exception $e) {
            // Handle exception
        }
        return $data;
    }

    public function importSkuData(Request $request)
    {
        $file = $request->file('file');
        $filePath = $file->getPathname();
        $data = $this->readExcelFile($filePath);
        $skuData = [];
        $currentSku = '';
        $groupName = '';
        $printLocation = '';
        foreach ($data as $key => $row) {
            if ($key == 0) {
                continue;
            }
            if (!empty($row[1])) {
                $currentSku = $row[1];
            }
            if (!empty($row[0])) {
                $groupName = $row[0];
            }
            if (!empty($row[2]) && in_array($row[2], ['Back print', 'Front print'])) {
                $printLocation = $row[2];
            }
            
            $skuData[] = [
                'name' => strip_tags($groupName),
                'sku' => $currentSku,
                'print_location' => $printLocation,
                'size' => $row[3],
                'material' => $row[4],
                'price' => $row[5],
                'created_at' => date('Y-m-d H:i:s'),
            ];
        }
        
        if(!empty($skuData)) {
            $this->saveSkuData($skuData);
        }

        return response()->json([
            'status' => 'success',
            'msg' => 'Imported successfully!',
            'data' => $skuData
        ], 200);
    }

    protected function saveSkuData($skuData)
    {
        \DB::table('bondre_product_sku')->delete();
        \DB::table('bondre_product_sku')->insert($skuData);
    }

    public function getProductSku () {

        $dataCacheKey = 'BONDRE_PRODUCT_SKU_' . config('app.version');
        if (Cache::has($dataCacheKey)) {

            $productTypes = Cache::get($dataCacheKey, []);

        } else {

            $productTypes = \DB::table('bondre_product_sku')->get();

            Cache::put($dataCacheKey, $productTypes, 3600);

        }

        return $productTypes;
    }

}
