<?php

namespace Modules\Transaction\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;

use App\Http\Models\User;
use App\Http\Models\Outlet;
use App\Http\Models\Product;
use App\Http\Models\ProductPrice;
use App\Http\Models\ProductModifierProduct;
use App\Http\Models\Courier;
use App\Http\Models\UserAddress;
use App\Http\Models\ManualPaymentMethod;
use App\Http\Models\UserOutlet;
use App\Http\Models\Configs;
use Modules\Brand\Entities\BrandProduct;

use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
use Guzzle\Http\EntityBody;
use Guzzle\Http\Message\Request as RequestGuzzle;
use Guzzle\Http\Message\Response as ResponseGuzzle;
use Guzzle\Http\Exception\ServerErrorResponseException;

use Modules\Transaction\Http\Requests\Transaction\DumpData;

use App\Lib\MyHelper;

class ApiDumpController extends Controller
{
    var $token = 'ampas';

    function __construct() {
        ini_set('max_execution_time', 0);
        date_default_timezone_set('Asia/Jakarta');
    }

    public function dumpData(DumpData $request) {
        $post = $request->json()->all();

        for ($dataCount=0; $dataCount < $post['how_many']; $dataCount++) {
            $dataItem = [];

            $date_start = strtotime($post['date_start']);
            $date_end   = strtotime($post['date_end']);
            $date       = date('Y-m-d H:i:s', rand($date_start, $date_end));

            $time_start = strtotime('08:00:00');
            $time_end   = strtotime('22:00:00');
            $time       = date('H:i:s', rand($time_start, $time_end));

            //user
            if(isset($post['id_user'])){
                if(is_array($post['id_user'])){
                    $idUser = $post['id_user'][array_rand($post['id_user'])];
                }else{
                    $idUser = $post['id_user'];
                }
            }else{
                $dataUser = User::get()->toArray();
                if (empty($dataUser)) {
                    return response()->json([
                        'status'    => 'fail',
                        'messages' => ['User is empty']
                    ]);
                }
                $splitUser = array_column($dataUser, 'id');
                $idUser = $splitUser[array_rand($splitUser)];
            }

            $user = User::where('id', $idUser)->first();

            $configDeliveryOrder = Configs::where('config_name', 'delivery order')->first();
            $configPickupOrder = Configs::where('config_name', 'pickup order')->first();

            //user address
            if($configDeliveryOrder && $configDeliveryOrder->is_active == '1'){
                $dataUserAddress = UserAddress::where('id_user', $idUser)->get()->toArray();
                if (empty($dataUserAddress)) {
                    return response()->json([
                        'status'    => 'fail',
                        'messages' => [$user['name'].' dont have user address']
                    ]);
                }
                $splitUserAddress = array_column($dataUserAddress, 'id_user_address');
                $getUserAddress = array_rand($splitUserAddress);
            }

            //outlet
            $dataOutlet = Outlet::select('outlets.id_outlet')
                                ->rightJoin('product_prices', 'outlets.id_outlet', 'product_prices.id_outlet')
                                ->whereNotNull('product_price')->whereNotNull('product_price_base')->whereNotNull('product_price_tax')
                                ->distinct()
                                ->get()->toArray();

            if (empty($dataOutlet)) {
                return response()->json([
                    'status'    => 'fail',
                    'messages' => ['Outlet is empty']
                ]);
            }

            $splitOutlet = array_column($dataOutlet, 'id_outlet');

            $getOutlet = array_rand($splitOutlet);


            //product
            $dataProduct = ProductPrice::where('id_outlet', $splitOutlet[$getOutlet])->where('product_price', '>',  0)->where('product_stock_status', 'Available')->get()->toArray();

            if (empty($dataProduct)) {
                return response()->json([
                    'status'    => 'fail',
                    'messages' => ['Product is empty']
                ]);
            }

            $splitProduct = array_column($dataProduct, 'id_product');

            $getProduct = array_rand($splitProduct);

            $totalItem = 0;
            $totalPrice = 0;

            $priceMin = 0;
            if(isset($post['price_start'])){
                $priceMin = $post['price_start'];
            }

            $qtyMin = 0;
            if(isset($post['qty_start'])){
                $qtyMin = $post['qty_start'];
            }

            if(isset($post['qty_end'])){
                $qtyEnd = $post['qty_end'];
            }else{
                $qtyEnd = 4;
            }

            do{
                $getItem = rand(1,count($dataProduct));

                for ($i=1; $i <= $getItem; $i++) {
                    $setProduct = array_column($dataProduct, 'id_product');
                    $insertProduct = array_rand($setProduct);

                    if (!empty($dataItem)) {
                        $checkIdProduct = array_column($dataItem, 'id_product');
                        if (!in_array($setProduct[$insertProduct], $checkIdProduct)) {
                            $modifier = [];
                            $mod = ProductModifierProduct::where('id_product', $setProduct[$insertProduct])->first();
                            $brand = BrandProduct::where('id_product', $setProduct[$insertProduct])->first();
                            if($mod){
                                $modifier[] = $mod['id_product_modifier'];
                            }
                            $setItem = [
                                'id_brand'   => $brand['id_brand'],
                                'id_product' => $setProduct[$insertProduct],
                                'qty'        => rand(1,$qtyEnd),
                                'note'       => $this->getrandomstring(),
                                'price'      => $dataProduct[$insertProduct]['product_price'],
                                'modifiers'   => $modifier
                            ];
                            $totalItem += $setItem['qty'];
                            $totalPrice += ($setItem['qty'] * $dataProduct[$insertProduct]['product_price']);
                        } else {
                            $setItem = [];
                        }
                    } else {
                        $modifier = [];
                        $mod = ProductModifierProduct::where('id_product', $setProduct[$insertProduct])->first();
                        $brand = BrandProduct::where('id_product', $setProduct[$insertProduct])->first();
                        if($mod){
                            $modifier[] = $mod['id_product_modifier'];
                        }
                        $setItem = [
                            'id_brand'   => $brand['id_brand'],
                            'id_product' => $setProduct[$insertProduct],
                            'qty'        => rand(1,$qtyEnd),
                            'note'       => $this->getrandomstring(),
                            'price'      => $dataProduct[$insertProduct]['product_price'],
                            'modifiers'   => $modifier
                        ];
                        $totalItem += $setItem['qty'];
                        $totalPrice += ($setItem['qty'] * $dataProduct[$insertProduct]['product_price']);
                    }

                    if (!empty($setItem)) {
                        array_push($dataItem, $setItem);
                    }

                    //harga sudah melebihi maksimal
                    if(isset($post['price_end'])){
                        if($totalPrice >= $post['price_end']){
                            break;
                        }
                    }

                    //jumlah item sudah melebihi maksimal
                    if(isset($post['qty_end'])){
                        if($totalItem >= $post['qty_end']){
                            break;
                        }
                    }
                }
            }while(($totalPrice < $priceMin) || ($totalItem < $qtyMin));

            if(isset($post['price_end'])){
                while($totalPrice > $post['price_end']){
                    if(count($dataItem) > 1 || (count($dataItem) == 1 && $dataItem[0]['qty'] > 1)){
                        if($dataItem[0]['qty'] > 1){
                            $dataItem[0]['qty'] -= 1;
                            $totalPrice -= $dataItem[0]['price'];
                        }else{
                            $totalPrice -= $dataItem[0]['price'];
                            array_splice($dataItem, 0, 1);
                        }
                    }
                }
            }

            if(isset($post['qty_end'])){
                while($totalItem > $post['qty_end']){
                    if($totalItem > $post['qty_end'] && (count($dataItem) > 1 || (count($dataItem) == 1 && $dataItem[0]['qty'] > 1))){
                        if($dataItem[0]['qty'] > 1){
                            $dataItem[0]['qty'] -= 1;
                        }else{
                            array_splice($dataItem, 0, 1);
                        }
                        $totalItem -= 1;
                    }
                }
            }


            $type = [];
            if($configDeliveryOrder && $configDeliveryOrder->is_active == '1'){
                $type[] = 'Delivery';

                //courier
                $getCourier = $this->courierSet();
                if (isset($getCourier['status']) && $getCourier['status'] == 'success') {
                    $setCourier = $getCourier['courier'];
                    if (!empty($getCourier['service'])) {
                        $splitService = array_rand($getCourier['service']);
                        $setCourierService = $getCourier['service'][$splitService];
                    } else {
                        $setCourierService = [];
                    }
                } elseif (isset($getCourier['status']) && $getCourier['status'] == 'fail') {
                    return response()->json([
                        'status'    => 'fail',
                        'messages' => [$getCourier['messages']]
                    ]);
                } else {
                    return response()->json([
                        'status'    => 'fail',
                        'messages' => ['Data Not Valid']
                    ]);
                }
            }

            if($configPickupOrder && $configPickupOrder->is_active == '1'){
                $type[] = 'Pickup Order';
            }

            $getType = array_rand($type);

            //payment
            $payment = ['Midtrans'];

            $configManualPayment = Configs::where('config_name', 'manual payment')->first();
            if($configManualPayment && $configManualPayment->is_active == '1'){
                $payment[] = 'Manual';
            }

            $getPayment = array_rand($payment);

            //manual_payment_method
            if($payment[$getPayment] == 'Manual'){
                $dataManualMethod = ManualPaymentMethod::get()->toArray();
                if (empty($dataManualMethod)) {
                    return response()->json([
                        'status'    => 'fail',
                        'messages' => ['Manual Payment Method is empty']
                    ]);
                }

                $splitManualMethod = array_column($dataManualMethod, 'id_manual_payment_method');
                $getManualMethod = array_rand($splitManualMethod);

                //bank_payment
                $accountBank = ManualPaymentMethod::with('manual_payment')->where('id_manual_payment_method', $splitManualMethod[$getManualMethod])->first();
            }

            //tax
            $setShip =  [ '15000', '16000', '17000', '18000', '19000', '20000', '21000', '22000', '23000', '24000', '25000', '26000', '27000', '28000', '29000', '30000', '31000', '32000', '33000', '34000', '35000', '36000', '37000', '38000', '39000', '40000', '41000', '42000', '43000', '44000', '45000', '46000', '47000', '48000', '49000', '50000', '51000', '52000', '53000', '54000', '55000', '56000', '57000', '58000', '59000', '60000', '61000', '62000', '63000', '64000'];

            $getShip = array_rand($setShip);

            if ($type[$getType] == 'Delivery') {
                $data = [
                    'id_outlet'                  => $splitOutlet[$getOutlet],
                    'id_user'                    => $idUser,
                    'type'                       => 'Delivery',
                    'notes'                      => $this->getrandomstring(),
                    'shipping'                   => $setShip[$getShip],
                    'courier'                    => $getCourier['courier'],
                    'cour_service'               => $setCourierService,
                    'cour_etd'                   => '1-2',
                    'id_user_address'            => $splitUserAddress[$getUserAddress],
                    'transaction_date'           => $date,
                    'payment_type'               => $payment[$getPayment],
                    'transaction_payment_status' => 'Completed'
                ];

                $configAdminOutlet = Configs::where('config_name', 'admin outlet')->first();
                if($configAdminOutlet && $configAdminOutlet->is_active == '1'){
                    $configAdminOutlet = Configs::where('config_name', 'admin outlet delivery order')->first();

                    if($configAdminOutlet && $configAdminOutlet->is_active == '1'){
                        $adminOutlet = UserOutlet::where('id_outlet', $data['id_outlet'])->where('delivery', 1)->get()->toArray();
                        if (empty($adminOutlet)) {
                            return response()->json([
                                'status'    => 'fail',
                                'messages' => ['Admin Outlet is empty']
                            ]);
                        }

                        $splitAdminOutlet = array_column($adminOutlet, 'id_user_outlet');
                        $getAdminOutlet = array_rand($splitAdminOutlet);

                        // return $splitAdminOutlet[$getAdminOutlet];

                        $data['receive_at']              = $date.' '.$time;
                        $data['id_admin_outlet_receive'] = $splitAdminOutlet[$getAdminOutlet];
                        $data['send_at']                 = $date.' '.$time;
                        $data['id_admin_outlet_send']    = $splitAdminOutlet[$getAdminOutlet];
                    }
                }

                $data['item'] = $dataItem;

                if ($payment[$getPayment] == 'Manual') {
                    $data['id_manual_payment_method'] = $splitManualMethod[$getManualMethod];
                    $data['payment_date']             = date('Y-m-d', strtotime($date));
                    $data['payment_time']             = $time;
                    $data['payment_bank']             = $accountBank['manual_payment']['manual_payment_name'];
                    $data['payment_method']           = $accountBank['payment_method_name'];
                    $data['payment_account_number']   = $accountBank['manual_payment']['account_number'];
                    $data['payment_account_name']     = $accountBank['manual_payment']['account_name'];
                    $data['payment_receipt_image']    = $this->image();
                    $data['payment_note']             = $this->getrandomstring();
                }

                $insertTransaction = $this->insert($data);
                // return $insertTransaction;
                if (isset($insertTransaction['status']) && $insertTransaction['status'] == 'success') {
                    continue;
                } elseif (isset($insertTransaction['status']) && $insertTransaction['status'] == 'fail') {
                    return response()->json([
                        'status'    => 'fail',
                        'messages' => $insertTransaction['messages']
                    ]);
                } else {
                    return response()->json([
                        'status'    => 'fail',
                        'messages' => ['Failed']
                    ]);
                }
            } else {
                $pickupType = ['set time', 'right now', 'at arrival'];
                $getPickupType = array_rand($pickupType);

                $data = [
                    'id_outlet'                  => $splitOutlet[$getOutlet],
                    'id_user'                    => $idUser,
                    'type'                       => 'Pickup Order',
                    'notes'                      => $this->getrandomstring(),
                    'pickup_type'                => $pickupType[$getPickupType],
                    'pickup_at'                  => date('Y-m-d', strtotime($date)).' '.$time,
                    'transaction_date'           => date('Y-m-d', strtotime($date)).' '.$time,
                    'payment_type'               => $payment[$getPayment],
                    'transaction_payment_status' => 'Completed'
                ];

                $data['item'] = $dataItem;

                $configAdminOutlet = Configs::where('config_name', 'admin outlet')->first();
                if($configAdminOutlet && $configAdminOutlet->is_active == '1'){
                    $configAdminOutlet = Configs::where('config_name', 'admin outlet pickup order')->first();

                    if($configAdminOutlet && $configAdminOutlet->is_active == '1'){

                        $adminOutlet = UserOutlet::where('id_outlet', $data['id_outlet'])->where('pickup_order', 1)->get()->toArray();
                        if (empty($adminOutlet)) {
                            return response()->json([
                                'status'    => 'fail',
                                'messages' => ['Admin Outlet is empty']
                            ]);
                        }

                        $splitAdminOutlet = array_column($adminOutlet, 'id_user_outlet');
                        $getAdminOutlet = array_rand($splitAdminOutlet);

                        $data['receive_at']              = $date.' '.$time;
                        $data['id_admin_outlet_receive'] = $splitAdminOutlet[$getAdminOutlet];
                        $data['taken_at']                = $date.' '.$time;
                        $data['id_admin_outlet_taken']   = $splitAdminOutlet[$getAdminOutlet];
                    }
                }

                if ($payment[$getPayment] == 'Manual') {
                    $data['id_manual_payment_method'] = $splitManualMethod[$getManualMethod];
                    $data['payment_date']             = date('Y-m-d', strtotime($date));
                    $data['payment_time']             = $time;
                    $data['payment_bank']             = $accountBank['manual_payment']['manual_payment_name'];
                    $data['payment_method']           = $accountBank['payment_method_name'];
                    $data['payment_account_number']   = $accountBank['manual_payment']['account_number'];
                    $data['payment_account_name']     = $accountBank['manual_payment']['account_name'];
                    $data['payment_receipt_image']    = $this->image();
                    $data['payment_note']             = $this->getrandomstring();
                }

                $insertTransaction = $this->insert($data);

                if (isset($insertTransaction['status']) && $insertTransaction['status'] == 'success') {
                    continue;
                } elseif (isset($insertTransaction['status']) && $insertTransaction['status'] == 'fail') {
                    return response()->json([
                        'status'    => 'fail',
                        'messages' => $insertTransaction['messages']
                    ]);
                } else {
                    return response()->json([
                        'status'    => 'fail',
                        'messages' => ['Failed']
                    ]);
                }
            }
        }

        return response()->json([
            'status' => 'success',
            'result' => 'Input '.$dataCount.' Data Transaction Success'
        ]);
    }

    public function insert($data) {
        $url = config('url.api_url').'api/transaction/be/new';

        $create = $this->sendStatus($url, $data);

        return $create;
    }

    public function getrandomstring($length = 15) {

       global $template;
       settype($template, "string");

       $template = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

       settype($length, "integer");
       settype($rndstring, "string");
       settype($a, "integer");
       settype($b, "integer");

       for ($a = 0; $a <= $length; $a++) {
               $b = rand(0, strlen($template) - 1);
               $rndstring .= $template[$b];
       }

       return $rndstring;
    }

    public function courierSet() {
        $dataCourier = Courier::get()->toArray();
        if (empty($dataCourier)) {
            return ['status' => 'fail', 'messages' => ['Courier is empty']];
        }

        $splitCourier = array_column($dataCourier, 'short_name');
        $getCourier = array_rand($splitCourier);

        if ($splitCourier[$getCourier] == 'jne') {
            $courierService = [
                'OKE', 'REG', 'YES'
            ];
        } elseif ($splitCourier[$getCourier] == 'ncs') {
            $courierService = [
                'NRS', 'ONS'
            ];
        } elseif ($splitCourier[$getCourier] == 'pcp') {
            $courierService = [
                'ONS', 'NFS', 'REG'
            ];
        } elseif ($splitCourier[$getCourier] == 'dse') {
            $courierService = [
                'SDS', 'ONS', 'ECO'
            ];
        } elseif ($splitCourier[$getCourier] == 'psc') {
            $courierService = [
                'SDS', 'ONS', 'ECO'
            ];
        } elseif ($splitCourier[$getCourier] == 'pos') {
            $courierService = [
                'Paket Kilat Khusus', 'Express Next Day Barang', 'Paketpos Dangerous Goods', 'Paketpos Valuable Goods'
            ];
        } elseif ($splitCourier[$getCourier] == 'tiki') {
            $courierService = [
                'REG', 'ONS', 'ECO', 'SDS', 'HDS'
            ];
        } elseif ($splitCourier[$getCourier] == 'esl') {
            $courierService = [
                'RPX/RDX'
            ];
        } elseif ($splitCourier[$getCourier] == 'rpx') {
            $courierService = [
                'SDP', 'MDP', 'NDP', 'RGP'
            ];
        } elseif ($splitCourier[$getCourier] == 'pandu') {
            $courierService = [
                'REG'
            ];
        } elseif ($splitCourier[$getCourier] == 'wahana') {
            $courierService = [
                'DES'
            ];
        } elseif ($splitCourier[$getCourier] == 'sicepat') {
            $courierService = [
                'REG', 'BEST', 'Priority'
            ];
        } elseif ($splitCourier[$getCourier] == 'jnt') {
            $courierService = [
                'EZ'
            ];
        } elseif ($splitCourier[$getCourier] == 'pahala') {
            $courierService = [
                'EXPRESS', 'ONS', 'SDS'
            ];
        } elseif ($splitCourier[$getCourier] == 'sap') {
            $courierService = [
                'REG', 'SDS', 'ODS'
            ];
        } elseif ($splitCourier[$getCourier] == 'jet') {
            $courierService = [
                'CRG', 'PRI', 'REG'
            ];
        } elseif ($splitCourier[$getCourier] == 'slis') {
            $courierService = [
                'REGULAR', 'EXPRESS'
            ];
        } elseif ($splitCourier[$getCourier] == 'first') {
            $courierService = [
                'REG', 'ONS', 'SDS'
            ];
        } elseif ($splitCourier[$getCourier] == 'star') {
            $courierService = [
                'Express', 'Reguler', 'Dokumen', 'MOTOR', 'MOTOR 150 - 250 CC'
            ];
        } else {
            $courierService = ['No Service'];
        }

        $data = [
            'status' => 'success',
            'courier' => $splitCourier[$getCourier],
            'service' => $courierService
        ];

        return $data;
    }

    public function sendStatus($url, $data) {
        $client = new Client;
        $content = array(
          'headers' => [
            'Authorization' => 'Bearer '.$this->getBearerToken(),
            'Accept'        => 'application/json',
            'Content-Type'  => 'application/json'
          ],
          'json' => (array) $data
        );

        try {
          $response =  $client->request('POST', $url, $content);
          return json_decode($response->getBody(), true);
        }
        catch (\GuzzleHttp\Exception\RequestException $e) {
          try{

            if($e->getResponse()){
              $response = $e->getResponse()->getBody()->getContents();
              // print_r($response); exit();
              $error = json_decode($response, true);

              if(!$error) {
                return $e->getResponse()->getBody();
              }
              else {
               return $error;
              }
            }
            else return ['status' => 'fail', 'messages' => [0 => 'Check your internet connection.']];

          }
          catch(Exception $e){
            return ['status' => 'fail', 'messages' => [0 => 'Check your internet connection.']];
          }
        }

    }

    function getAuthorizationHeader(){
        $headers = null;
        if (isset($_SERVER['Authorization'])) {
            $headers = trim($_SERVER["Authorization"]);
        } else if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
            $headers = trim($_SERVER["HTTP_AUTHORIZATION"]);
        } elseif (function_exists('apache_request_headers')) {
            $requestHeaders = apache_request_headers();
            $requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
            if (isset($requestHeaders['Authorization'])) {
                $headers = trim($requestHeaders['Authorization']);
            }
        }

        if (!empty($headers)) {
            if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
                return $matches[1];
            }
        }

        if (isset($_SERVER['REDIRECT_HTTP_AUTHENTICATION']) && $headers == null){
            $headers = trim($_SERVER["REDIRECT_HTTP_AUTHENTICATION"]);
        }

        if (isset($_SERVER['REDIRECT_REDIRECT_HTTP_AUTHORIZATION']) && $headers == null){
            $headers = trim($_SERVER["REDIRECT_REDIRECT_HTTP_AUTHORIZATION"]);
        }

        return $headers;

        return $headers;
    }

    function getBearerToken() {
        $headers = $this->getAuthorizationHeader();
        if (!empty($headers)) {
            if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
                return $matches[1];
            }else{
                return $headers;
            }
        }

        return null;
    }

    public function image() {
        return ' ';
    }

    public function generateNumber() {
        return $this->token;
        $data = 15000;
        do {
            echo $data.' ';
            $data += 1000;
        } while ($data < 65000);
    }
}
