<?php

/**
 * pos_register table's controller.
 *
 * Used to perform operations on pos_register table.
 *
 * @author Mario Vallejo <wappsi.desarrollomovil01@gmail.com>
 */

namespace App\Controllers;

use App\Models\SmaPaymentMethodsModel;
use App\Models\SmaPosRegisterItemsModel;
use App\Models\SmaPosRegisterModel;
use App\Models\SmaPosRegisterMovementsModel;
use App\Models\SmaSalesModel;
use CodeIgniter\RESTful\ResourceController;

class SmaPosRegister extends ResourceController
{
    /**
     * Verify if there is a pos_register opened for user.
     *
     * Given a user_id, verify if there is a pos_register row opened, if there is at least
     * one, returns it's data.
     *
     * @param int  $idUser   user_id to verify
     *      
     *
     * @return  array
     */
    public static function verify($idUser, $dbGroup)
    {

        $register = new SmaPosRegisterModel($dbGroup);

        $register_open = $register->where(['user_id' => $idUser, 'status' => 'open'])->first();

        if (empty($register_open)) {
            $register_open = [
                'status' => 'close',
            ];
        } else {
            $register_open = [
                'status' => $register_open['status'],
                'id' => $register_open['id'],
                'date' => $register_open['date'],
                'user_id' => $register_open['user_id'],
                'cash_in_hand' => $register_open['cash_in_hand'],
                'movements_in' => $register_open['movements_in'],
                'total_retention' => $register_open['total_retention'],
                'total_return_retention' => $register_open['total_return_retention'],
                'total_rc_retention' => $register_open['total_rc_retention'],
                'registration_date' => $register_open['registration_date'],
            ];
        }

        return $register_open;
    }

    /**
     * Open a pos_register for a user.
     *
     * Given a base value from request, create a new row on pos_register for the autenticated
     * request user and returns it's new pos_register data.
     *
     * @return HttpResponse 
     */
    public function open()
    {

        $rules = [
            'base' => 'required|numeric',
        ];
        $this->request;
        $message = [
            'base' => [
                'required' => 'Base requerida',
            ],
        ];

        // echo $this->request->();

        if (!$this->validate($rules, $message)) {

            // if validation fails

            $response = [
                'status' => 400,
                'error' => true,
                'base' => $this->request->getVar('base'),
                'message' => $this->validator->getErrors(),
                'data' => [],
            ];

            return $this->respondCreated($response);
        } else {

            $register = new SmaPosRegisterModel($this->dbGroupFromRequest());
            // GET USER_ID FROM TOKEN
            $authHeader = $this->request->getServer('HTTP_AUTHORIZATION');
            helper('jwt');
            $token = getJWTFromRequest($authHeader);

            helper('jwt');
            $userId = userIdFromJWT($token);

            $register_open = $this->verify($userId, $this->dbGroupFromRequest(),);

            // IF ALREADY OPENED
            if ($register_open['status'] == 'close') {
                // open
                $query = [

                    'status' => 'open',
                    'user_id' => $userId,
                    'cash_in_hand' => $this->request->getVar('base'),
                    'movements_in' => 0,
                    'total_retention' => 0,
                    'total_rc_retention' => 0,
                    'total_return_retention' => 0,

                ];
                // echo $query;
                $register->save($query);

                $register_open = $this->verify($userId, $this->dbGroupFromRequest(),);

                if (empty($register_open)) {
                    $response = [
                        'status' => 400,
                        'error' => true,
                        'message' => 'Error al abrir caja, intente nuevamente',
                        'register_data' => [],
                    ];

                    return $this->respondCreated($response);
                } else {
                    $response = [
                        'status' => 201,
                        'error' => false,
                        'message' => 'Caja abierta correctamente',
                        'register_data' => $register_open,
                    ];

                    return $this->respondCreated($response);
                }
            } else {
                $response = [
                    'status' => 200,
                    'error' => false,
                    'message' => 'Caja abierta anteriormente',
                    'register_data' => $register_open,
                ];

                return $this->respondCreated($response);
            }

            // Return current date from the remote server
            // $date = date('yy-m-d h:i:s');

            // echo $date;
        }
    }

    /**
     * Close pos_register.
     *
     * Given total_cash_submitted value from request, close pos register for the user who 
     * generate the request.
     *
     * @return HttpResponse 
     */
    public function close()
    {
        $rules = [
            'total_cash_submitted' => 'required|numeric',
        ];
        $this->request;
        $message = [
            'total_cash_submitted' => [
                'required' => 'Total digitado por el usuario requerido',
            ],
        ];
        if (!$this->validate($rules, $message)) {

            // if validation fails

            $response = [
                'status' => 400,
                'error' => true,
                'message' => $this->validator->getErrors(),
            ];

            return $this->respondCreated($response);
        } else {
            $this->setModel(new SmaPosRegisterModel($this->dbGroupFromRequest()));
            $register = new SmaPosRegisterModel($this->dbGroupFromRequest());
            // GET USER_ID FROM TOKEN
            $authHeader = $this->request->getServer('HTTP_AUTHORIZATION');
            helper('jwt');
            $token = getJWTFromRequest($authHeader);

            helper('jwt');
            $userId = userIdFromJWT($token);

            $register_info = $this->verify($userId, $this->dbGroupFromRequest(),);
            // check if user have an existing open register
            if (empty($register_info) || $register_info['status'] == 'close') {
                $response = [
                    'status' => 400,
                    'error' => true,
                    'message' => 'No se encontro caja abierta',
                ];

                return $this->respondCreated($response);
            } else {

                // close register before continue
                $closed_at = $this->getServerDateTime();
                $payment = $this->otherPaymentMethods($userId, $register_info['date'], $closed_at, $this->dbGroupFromRequest(),);

                $movements = $this->registerMovements($userId, $register_info['date'], $closed_at, $this->dbGroupFromRequest(),);


                //movements: '1' key is for cash in and '2' to cash out of register
                $total_cash = ($payment[0]['cash'] ?? 0) + $register_info['cash_in_hand'] + $movements['1'] - $movements['2'];

                // print_r([$total_cash,$movements]);

                $data = [
                    'status' => 'close',
                    'closed_by' => $userId,
                    'closed_at' => $closed_at,
                    'total_cash' => $total_cash,
                    'total_cash_submitted' => $this->request->getVar('total_cash_submitted'),

                ];

                // print_r($data);
                $res = $register->update($register_info['id'], $data);

                // //if register gets closed
                if ($res) {
                    // if (true) {
                    // remove cash payment before add register items
                    // unset($payment[0]['cash']);
                    if (count($payment[0]) >= 1) {
                        $grandTotal = $this->grantTotal($userId, $register_info['date'], $closed_at, $this->dbGroupFromRequest());
                        $creditPay = $grandTotal - $payment[1];

                        // register_items
                        $res2 = $this->registerItems($payment[0], $creditPay, $register_info['id'], $this->dbGroupFromRequest());

                        //if error
                        if ($res2 == false) {
                            $data = [
                                'status' => 'open',
                                'closed_by' => null,
                                'closed_at' => null,
                                'total_cash' => null,
                                'total_cash_submitted' => null,

                            ];

                            // print_r($data);
                            $res = $register->update($register_info['id'], $data);

                            $response = [
                                'status' => 400,
                                'error' => true,
                                'message' => 'Error al registrar items de caja, estado de caja revertido',
                            ];

                            return $this->respondCreated($response);
                        }
                    }

                    $response = [
                        'status' => 200,
                        'error' => false,
                        'date' => $closed_at ?? null,
                        'message' => 'Caja cerrada correctamente',
                    ];

                    return $this->respondCreated($response);
                    // get credit sales value

                } else {
                    // return error
                    $response = [
                        'status' => 400,
                        'error' => true,
                        'message' => 'Error al cerrar caja, intente nuevamente',
                    ];

                    return $this->respondCreated($response);
                }
            }
        }
    }
    /**
     * Gets all payments total in sales from register
     *
     *
     * @return double
     */
    public function total_cash(int $user_id, String $startDate, String $endDate, $base, $dbGroup)
    {
        $sales = new SmaSalesModel($dbGroup);
        $where = "sma_sales.created_by='$user_id' and sma_sales.date between
        STR_TO_DATE('$startDate', '%Y-%m-%d %H:%i:%s') and
        STR_TO_DATE('$endDate', '%Y-%m-%d %H:%i:%s')";
        // echo $where;
        $salesFromRegister = $sales->selectSum('sma_payments.amount')
            ->join('sma_payments', "sma_payments.sale_id=sma_sales.id and sma_payments.paid_by='cash'")
            ->where($where)->first();
        // print_r($sales->getLastQuery());
        // print_r($salesFromRegister);

        return $salesFromRegister['amount'] + $base;
    }
    /**
     * Gets all pay total in sales from register of current user and the total of them in
     * an array, wich [0]->each payment total and [1]->total of all.
     *
     *
     * @return array
     */
    public function otherPaymentMethods(int $user_id, String $startDate, String $endDate, $dbGroup)
    {
        $sales = new SmaSalesModel($dbGroup);
        $where = "sma_sales.created_by='$user_id' and sma_sales.date between
        STR_TO_DATE('$startDate', '%Y-%m-%d %H:%i:%s') and
        STR_TO_DATE('$endDate', '%Y-%m-%d %H:%i:%s')";
        // echo $where;
        $salesFromRegister = $sales
            ->select('SUM(sma_payments.amount) AS total ,sma_payments.paid_by')
            ->join('sma_payments', "sma_payments.sale_id=sma_sales.id AND sma_payments.paid_by!='Credito'")
            ->where($where)->groupBY('sma_payments.paid_by')->get()->getResultArray();
        // print_r($sales->getLastQuery());
        $result = [];
        $total_paid = 0;

        foreach ($salesFromRegister as $paymentMethod) {
            $result[$paymentMethod['paid_by']] = $paymentMethod['total'];

            // to not sum Credit payments in paied total
            // if($paymentMethod['paid_by']!='Credito'){
            $total_paid += $paymentMethod['total'];
            // }
        }

        return [$result, $total_paid];
    }

    /**
     * Get all register movements grouping by its type
     *
     *
     * @return array
     */
    public function registerMovements(int $user_id, String $startDate, String $endDate, String $dbGroup)
    {
        $sales = new SmaPosRegisterMovementsModel($dbGroup);
        $where = "created_by='$user_id' and date between
        STR_TO_DATE('$startDate', '%Y-%m-%d %H:%i:%s') and
        STR_TO_DATE('$endDate', '%Y-%m-%d %H:%i:%s')";
        // echo $where;
        $salesFromRegister = $sales
            ->select('SUM(amount) AS total ,movement_type')
            ->where($where)->groupBY('movement_type')->get()->getResultArray();
        // print_r($sales->getLastQuery());
        $result = [];
        // $total_paid = 0;

        foreach ($salesFromRegister as $paymentMethod) {
            $result[$paymentMethod['movement_type']] = $paymentMethod['total'];

            // to not sum Credit payments in paied total
            // if($paymentMethod['paid_by']!='Credito'){
            // $total_paid += $paymentMethod['total'];
            // }
        }

        return $result;
    }

    /**
     * Gets total of sales for a user opened register
     *
     *
     * @return double
     */
    public function grantTotal(int $user_id, String $startDate, String $endDate, String $dbGroup)
    {
        $sales = new SmaSalesModel($dbGroup);
        $where = "sma_sales.created_by='$user_id' and sma_sales.date between
        STR_TO_DATE('$startDate', '%Y-%m-%d %H:%i:%s') and
        STR_TO_DATE('$endDate', '%Y-%m-%d %H:%i:%s')";
        // echo $where;
        $grandTotal = $sales->select('SUM(sma_sales.grand_total) AS grand_total')
            ->where($where)->first();
        // print_r($sales->getLastQuery());
        // print_r($grandTotal);

        return $grandTotal['grand_total'];
    }

    /**
     * Gets all payment methods info and return an array with payment method code as key
     *
     *
     * @return array
     */
    public function paymentMethods(String $dbGroup)
    {
        $paymentMethods = new SmaPaymentMethodsModel($dbGroup);
        // echo $where;
        $payMethods = $paymentMethods->select('*')
            ->get()->getResultArray();
        // print_r($sales->getLastQuery());
        $result = [];
        foreach ($payMethods as $payM) {
            $result[$payM['code']] = $payM;
        }

        return $result;
    }
    /**
     * Insert register items into db with a given array of payment methods total
     *
     *
     * @return array
     */
    public function registerItems(array $paymentMTotals, float $creditValue, int $posRegisterId, String $dbGroup)
    {
        $payMethods = $this->paymentMethods($dbGroup);
        $registerItems = new SmaPosRegisterItemsModel($dbGroup);
        // print_r($sales->getLastQuery());
        $query = [];
        if ($creditValue > 0.0) {
            $paymentMTotals['Credito'] = $creditValue;
        }
        foreach ($paymentMTotals as $key => $value) {
            $subQuery = [
                'pos_register_id' => $posRegisterId,
                'payment_method_id' => $payMethods[$key]['id'],
                'description' => $payMethods[$key]['name'],
                'sales_amount' => $value,
                'total_amount' => $value,
            ];
            array_push($query, $subQuery);
        }

        $res = $registerItems->insertBatch($query);

        return $res;
    }
}
