<?php

namespace Hura8\Components\Order\Model;


use Hura8\Components\Order\Controller\OrderStatus;
use Hura8\Interfaces\AppResponse;
use Hura8\Interfaces\iEntityModel;
use Hura8\Interfaces\iSearch;
use Hura8\Interfaces\EntityType;
use Hura8\System\Model\aEntityBaseModel;
use Hura8\System\Security\DataClean;
use Hura8\System\Security\DataType;
use Hura8\System\TimeManager;
use Hura8\System\Url;

class OrderModel extends aEntityBaseModel implements iEntityModel
{

    protected $tb_order_detail = "tb_order_detail";

    /* @var iSearch $objSearchModel */
    protected $objSearchModel;

    public function __construct() {

        $this->objSearchModel = new OrderSearchModel();

        parent::__construct(EntityType::ORDER, '', $this->objSearchModel);
    }


    protected function extendedFilterOptions() : array
    {
        return [
            // empty for now
        ];
    }


    public function getItems($orderId, $fields = "*") {
        $query = $this->db->runQuery(
            " SELECT ".$fields." FROM `".$this->tb_order_detail."` WHERE `order_id` = ? ",
            ['d'], [ $orderId ]);

        $order_item = array();
        foreach ( $this->db->fetchAll($query) as $info ) {

            $item_info = ($info["item_info"]) ? \json_decode($info["item_info"], true) : false;
            $in_cart   = ($info["in_cart"]) ? \json_decode($info["in_cart"], true) : false;


            $info['item_info'] = $item_info;
            $info['in_cart'] = $in_cart;

            $order_item[] = $info;
        }

        return $order_item;
    }

    //since we save the entire cart-structure for item_info, we need to re-construct it to make it easier to read and for various reporting/ email etc..
    protected function buildOrderItemInfo($item_type, array $item_info) {
        $new_info = [];

        if($item_type == 'product') {

            $new_info = System::stripProperty(array($item_info['info']), [
                "variant_option",
                'id',
                'productId',
                'priceUnit',
                'price',
                'currency',
                'lastUpdate',
                'warranty',
                'productName',
                'productUrl',
                'productModel',
                'productSummary',
                'marketPrice',
                'productImage',
                'brand',
                'visit',
                'rating',
                'reviewCount',
                'quantity',
                'productSKU',
                'hasVAT',
                'condition',
                'specialOffer',
                'specialOfferGroup',
                'productType',
                'thum_poster',
                'promotion_price',
                'addon'
            ])[0];

            //find variants bought
            if($new_info['config_count'] > 0) {

                foreach ($item_info['in_cart'] as $_variant) {
                    $new_info['variants'][] = array(
                        "id"            => $_variant['id'],
                        "sku"           => $_variant['sku'],
                        "title"         => $_variant['name'],
                        "image"         => ($_variant['image']) ? $_variant['image'] : $item_info['info']['productImage']["medium"],
                        "url"           => $item_info['info']['productUrl'],
                        "attribute"     => $_variant['attribute'],
                        "price"         => $_variant['price'],
                        "addon_total"   => 0,
                        "currency"      => $item_info['info']['currency'],
                        "priceUnit"     => $item_info['info']['priceUnit'],
                        "quantity"      => $_variant['quantity'],
                        "buyer_note"     => $_variant['buyer_note'],
                        "addon"     => [],
                        "promotion" => [
                            "list"  => $item_info['info']['specialOffer'],
                            "group" => (isset($_variant['promotion'])) ? $this->buildPromotionFromGroup( $item_info['info']['specialOfferGroup'], $_variant['promotion']) : $this->buildPromotionFromGroup( $item_info['info']['specialOfferGroup'], array() ),
                        ],
                        //..any other
                    );
                }

            }else{

                //product does not have variant
                $build_addon = [];
                $total_addon_price = 0;
                if(isset($item_info['info']['addon']) && isset($item_info['in_cart'][0]['addon'])) {
                    $build_addon = $this->getSelectedAddon($item_info['info']['addon'], $item_info['in_cart'][0]['addon']);
                    foreach ($build_addon as $addon) {
                        $total_addon_price += $addon['price'] * $addon['quantity'];
                    }
                }

                $variant_in_cart = (isset($item_info['in_cart'][0])) ? $item_info['in_cart'][0] : false;

                $new_info['variants'][] = array(
                    "id"            => 0,
                    "sku"           => $item_info['info']['productSKU'],
                    "title"         => $item_info['info']['productName'],
                    "image"         => $item_info['info']['productImage']["medium"],
                    "url"           => $item_info['info']['productUrl'],
                    "attribute"     => [],
                    "price"         => $item_info['info']['price'],
                    "addon_total"   => $total_addon_price,
                    "currency"      => $item_info['info']['currency'],
                    "priceUnit"     => $item_info['info']['priceUnit'],
                    "quantity"      => $variant_in_cart['quantity'],
                    "buyer_note"     => $variant_in_cart['buyer_note'],
                    "addon"         => $build_addon,
                    "promotion" => [
                        "list"  => $item_info['info']['specialOffer'],
                        "group" => (isset($variant_in_cart['promotion'])) ? $this->buildPromotionFromGroup( $item_info['info']['specialOfferGroup'], $variant_in_cart['promotion']) : $this->buildPromotionFromGroup( $item_info['info']['specialOfferGroup'], array() ),
                    ],
                    //..any other
                );
            }

            //
            return $new_info;
        }

        if($item_type == 'combo') {

            $new_info = [
                "price"         => $item_info['info']['sale_price'],
                "quantity"      => $item_info['in_cart']['quantity'],
                "buyer_note"    => $item_info['in_cart']['buyer_note'],
                "url"           => '',
            ];

            $new_info['product_list'] = System::stripProperty($item_info['info']['product_list'], [
                "variant_option",
                'id',
                'productId',
                'priceUnit',
                'price',
                'currency',
                'lastUpdate',
                'warranty',
                //'productName',
                //'productUrl',
                //'productModel',
                'productSummary',
                'marketPrice',
                'productImage',
                'brand',
                'visit',
                'rating',
                'reviewCount',
                'config_count',
                'quantity',
                //'productSKU',
                'hasVAT',
                'condition',
                'specialOffer',
                'specialOfferGroup',
                'productType',
                'thum_poster',
                'promotion_price',
                'addon',
                'imageCollection',
                'variants'
            ]);

            return $new_info;
        }

        if($item_type == 'deal') {

            $new_info = [
                "price"         => $item_info['info']['price'],
                "quantity"      => $item_info['in_cart']['quantity'],
                "buyer_note"    => $item_info['in_cart']['buyer_note'],
                "url"           => '/deal/'.$item_info['info']['id'],
            ];

            return $new_info;
        }

        return $new_info;
    }

    protected function getSelectedAddon($all_product_addons, $in_cart) {

        if(!is_array($all_product_addons) || !is_array($in_cart)) return [];

        $result = [];
        foreach ($all_product_addons as $item) {
            foreach ($in_cart as $selected) {
                if($item['addon_id'] == $selected['id']) {
                    $result[] = [
                        "id"    => $selected['id'],
                        "title" => $item['title'],
                        "price" => $item['price'],
                        "quantity" => (isset($selected['quantity'])) ? intval($selected['quantity']) : 1,
                        "related_article_url" => $item['related_article_url'],
                    ];
                }
            }
        }

        return $result;
    }

    protected function buildPromotionFromGroup( $offer_group, $selected_one_promotion) {

        if(!is_array($offer_group) && !is_array($selected_one_promotion)) return false;

        $promotion = [];

        foreach ($offer_group as $group) {
            if($group['type'] == 'one') {

                $selected_promotion = [];
                foreach ($group['promotion'] as $promo) {
                    foreach ($selected_one_promotion as $selected) {
                        if($selected['promotion_id'] == $promo['id'] && $selected['group_id'] == $group['id']) {
                            $selected_promotion[] = $promo;
                        }
                    }
                }

                $promotion[] = [
                    "id"        => $group['id'],
                    "title"     => $group['title'],
                    "note"      => $group['note'],
                    "promotion" => $selected_promotion,
                ];


            }else{
                $promotion[] = [
                    "id" => $group['id'],
                    "title" => $group['title'],
                    "note" => $group['note'],
                    "promotion" => $group['promotion'],
                ];
            }
        }

        return $promotion;

    }


    protected function getListFilterCondition($list_id) {

        if($list_id == 'mine') {
            return [
                'assign_to' => ADMIN_ID,
            ];
        }

        if($list_id == 'new') {
            return [
                'status' => 'new',
            ];
        }

        if($list_id == 'unpaid') {
            return [
                'payment' => 'unpaid',
            ];
        }

        if($list_id == 'partially-paid') {
            return [
                'payment' => 'partially-paid',
            ];
        }

        if($list_id == 'unfulfilled') {
            return [
                'fullfillment' => 'unfulfilled',
            ];
        }

        if($list_id == 'partially-fulfilled') {
            return [
                'fullfillment' => 'partially-fulfilled',
            ];
        }

        return null;
    }

    public function getStatusHistory($orderId){
        $query = $this->db->runQuery("
                                select * from ".TB_ORDER_STATUS_HISTORY."
                                WHERE order_id = ?
                                order by id desc
                                limit 100
                            ", ['d'], [ $orderId ] ) ;

        return $this->db->fetchAll($query);
    }

    public function getItemsForOrderList(array $list_ids, $fields = "*") {

        if(!sizeof($list_ids)) return [];

        list($parameterized_ids, $bind_types) = create_bind_sql_parameter_from_value_list($list_ids, 'int');

        $query = $this->db->runQuery("
                                SELECT ".$fields." FROM `".$this->tb_order_detail."`
                                WHERE `order_id` IN (".$parameterized_ids.")
                            ", $bind_types, $list_ids);

        $result = array();
        foreach ( $this->db->fetchAll($query) as $rs ) {

            $item_info = unserialize($rs['item_info']);
            if( isset($item_info["info"]) && isset($item_info["in_cart"])) {
                $rs['item_info'] = $this->buildOrderItemInfo($rs['item_type'], $item_info );
            } else {
                $rs['item_info'] = null;
            }

            $result[$rs['order_id']][] = $rs;
        }

        return $result;
    }

    protected function _buildQueryConditionExtend(array $conditions) : ?array
    {
        $catCondition = [];
        $bind_types = [];
        $bind_values = [];

        /*
        $conditions = array(
            'orderCode' => '',
            'query' => '',
            'coupon' => '',
            'cus_id' => '',
            'province' => '',
            'district' => '',
            'folder' => '',
            'view_status' => '',
            'update_by' => '',
            'shipping_status' => '',
            'assign_to' => '',
            'from_date' => '',
            'to_date' => '',
            'from_hour' => '',
            'to_hour' => '',
            'excluded_ids' => '',
            'included_ids' => '',
            'payment' => '',
            'fullfillment' => '',
            'list' => '',
        );*/


        // merge with special list
        if(isset($conditions['list']) && $conditions['list']) {
            $list_condition = $this->getListFilterCondition($conditions['list']);
            if($list_condition) {
                // update and over-write any key in $conditions if exist
                foreach ($list_condition as $key => $value) {
                    $conditions[$key] = $value;
                }
            }
        }

        if(isset($conditions['orderCode']) && $conditions['orderCode']) {
            $orderCode = DataClean::makeInputSafe($conditions['orderCode'],DataType::INTEGER);
            $catCondition[] = " AND `orderId` LIKE '".$orderCode."%' ";
        }

        if(isset($conditions['coupon']) && $conditions['coupon']) {
            $coupon = preg_replace("/[^a-z0-9_\-\.]/i","", $conditions['coupon']);
            if($coupon) $catCondition[] = " AND ( LENGTH(`order_discount`) > 10 AND `order_discount` LIKE '%".$coupon."%' ) ";
        }

        if(isset($conditions['cus_id']) && $conditions['cus_id']) {
            $catCondition[] = " AND buyerId = '".intval($conditions['cus_id'])."'";
        }

        if(isset($conditions['province']) && $conditions['province']) {
            $catCondition[] = " AND province = '".intval($conditions['province'])."'";
        }

        if(isset($conditions['district']) && $conditions['district']) {
            $catCondition[] = " AND district = '".intval($conditions['district'])."'";
        }

        if(isset($conditions['folder']) && $conditions['folder']) {
            $catCondition[] = " AND `folder` = '". preg_replace("/[^a-z0-9_\-\.]/i", "", $conditions['folder'])."' ";
        }

        if(isset($conditions['payment']) && array_key_exists($conditions['payment'], OrderStatus::PAYMENT_STATUS ) ) {
            $catCondition[] = " AND `payment_status` = '". $this->db->escape($conditions['payment'])."' ";
        }

        if(isset($conditions['fullfillment']) && array_key_exists($conditions['fullfillment'], OrderStatus::FULFILLMENT_STATUS) ) {
            $catCondition[] = " AND `fulfillment_status` = '". $this->db->escape($conditions['fullfillment'])."' ";
        }

        if(isset($conditions['status']) && array_key_exists($conditions['status'], OrderStatus::ORDER_STATUS) ) {
            $catCondition[] = " AND `order_status` = '". $this->db->escape($conditions['status'])."' ";
        }

        if(isset($conditions['view_status']) && $conditions['view_status']) {
            if($conditions['view_status'] == 'no-status') {
                $catCondition[] = " AND `status_id` = 0 ";
            } else {
                $catCondition[] = " AND `status_id` = '". intval($conditions['view_status'])."' ";
            }
        }

        if(isset($conditions['update_by']) && $conditions['update_by']) {
            $catCondition[] = " AND `status_update_by` = '". $this->db->escape($conditions['update_by'])."' ";
        }

        if(isset($conditions['shipping_status']) && $conditions['shipping_status']) {
            $catCondition[] = " AND `admin_shipping_status` = '". preg_replace("/[^a-z0-9_\-\.]/i", "", $conditions['shipping_status'])."' ";
        }

        if(isset($conditions['assign_to']) && $conditions['assign_to']) {
            $catCondition[] = " AND `assign_to` = '". intval($conditions['assign_to'])."' ";
        }

        //filter by date
        if(isset($conditions['from_date']) && $conditions['from_date']) {
            $catCondition[] = " AND order_time >= '". intval(strtotime(TimeManager::convert_date_from_javascript($conditions['from_date'])." 00:00"))."' ";
        }

        if(isset($conditions['to_date']) && $conditions['to_date']) {
            $catCondition[] = " AND order_time <= '".strtotime(TimeManager::convert_date_from_javascript($conditions['to_date'])." 23:59")."' ";
        }

        //filter by hour
        if(isset($conditions['from_hour']) && $conditions['from_hour']) {
            $catCondition[] = " AND `order_hour` >= '".intval($conditions['from_hour'])."' ";
        }
        if(isset($conditions['to_hour']) && $conditions['to_hour']) {
            $catCondition[] = " AND `order_hour` <= '".intval($conditions['to_hour'])."' ";
        }

        if(isset($conditions["excluded_ids"]) && $conditions["excluded_ids"] ){
            $list_ids = filterNumber(explode(",", $conditions["excluded_ids"]));
            if(sizeof($list_ids)) $catCondition[] = " AND `orderId` NOT IN (".join(',', $list_ids ).") ";
        }

        if(isset($conditions["included_ids"]) && $conditions["included_ids"] ){
            $list_ids = filterNumber(explode(",", $conditions["included_ids"]));
            if(sizeof($list_ids)) $catCondition[] = " AND `orderId` IN (".join(',', $list_ids ).") ";
        }


        return array( join(" ", $catCondition), $bind_types, $bind_values);
    }


    protected function beforeCreateItem(array $input_info) : AppResponse
    {
        $info = $input_info;

        if(isset($info['file_external_url'])) {
            if($info['file_external_url'] && !Url::isUrlValid($info['file_external_url'])) {
                $info['file_external_url'] = '';
            }
        }


        $info['create_time'] = CURRENT_TIME;
        $info['create_by'] = ADMIN_NAME;
        $info['last_update'] = CURRENT_TIME;
        $info['last_update_by'] = ADMIN_NAME;

        return new AppResponse('ok', null, $info);
    }


    protected function beforeUpdateItem($item_id, $current_item_info, $new_input_info) : AppResponse
    {
        $info = $new_input_info;

        unset($info['id']);

        if(isset($info['file_external_url']) && $info['file_external_url'] && !Url::isUrlValid($info['file_external_url'])) {
            $info['file_external_url'] = '';
        }

        $info['last_update'] = CURRENT_TIME;
        $info['last_update_by'] = ADMIN_NAME;

        return new AppResponse('ok', null, $info);
    }

    protected function beforeDeleteItem($item_id, $item_info) : AppResponse
    {
        return new AppResponse('ok');
    }

    protected function afterDeleteItem($item_id, $item_info)
    {

    }


    protected function afterCreateItem($new_item_id, $new_item_info)
    {

    }

    protected function afterUpdateItem($item_id, $old_item_info, $new_item_info)
    {

    }

}
