<?php

namespace addons\shopro\service\order;

use app\admin\model\shopro\order\Order;
use app\admin\model\shopro\order\OrderItem;
use app\admin\model\shopro\order\Action as OrderAction;
use app\admin\model\shopro\order\Express as OrderExpress;
use app\admin\model\shopro\activity\Groupon as ActivityGroupon;
use app\admin\model\shopro\activity\GrouponLog as ActivityGrouponLog;
use app\admin\model\shopro\dispatch\Dispatch as DispatchModel;
use app\admin\model\shopro\dispatch\DispatchAutosend;
use addons\shopro\library\express\Express as ExpressLib;



class OrderDispatch
{

    public $order = null;

    public function __construct($params = [])
    {
        if (isset($params['order_id']) && !empty($params['order_id'])) {

            $this->order = Order::find($params['order_id']);
            if (!$this->order) {
                error_stop('订单不存在');
            }
        }
    }


    /**
     * 执行发货
     *
     * @return object
     */
    public function confirm($params)
    {
        $admin = auth_admin();
        $method = $params['method'] ?? '';
        if (!in_array($method, ['input', 'api', 'upload'])) {
            error_stop('请使用正确的发货方式');
        }
        if ($this->order->status !== Order::STATUS_PAID && !$this->order->isOffline($this->order)) {
            error_stop("该订单{$this->order->status_text},不能发货");
        }

        if ($this->order->apply_refund_status === Order::APPLY_REFUND_STATUS_APPLY) {
            error_stop("该订单已申请退款,暂不能发货");
        }

        switch ($method) {
            case 'api':
                list($orderItems, $express) = $this->doByApi($params);
                break;
            case 'input':
                list($orderItems, $express) = $this->doByInput($params);
                break;
            case 'upload':
                list($orderItems, $express) = $this->doByUpload($params);
                break;
        }

        // 添加包裹信息
        $orderExpress = OrderExpress::create([
            'user_id' => $this->order->user_id,
            'order_id' => $this->order->id,
            'express_name' => $express['name'],
            'express_code' => $express['code'],
            'express_no' => $express['no'],
            'method' => $method,
            'driver' => $express['driver'] ?? null,
            'ext' => $express['ext'] ?? null
        ]);

        // 修改订单商品发货状态
        foreach ($orderItems as $orderItem) {
            $orderItem->order_express_id = $orderExpress->id;
            $orderItem->dispatch_status = OrderItem::DISPATCH_STATUS_SENDED;
            $orderItem->ext = array_merge($orderItem->ext, ['send_time' => time()]);    // item 发货时间
            $orderItem->save();
            OrderAction::add($this->order, $orderItem, $admin, 'admin', "商品{$orderItem->goods_title}已发货");
        }
        $this->subscribeExpressInfo($orderExpress);
        // 订单发货后
        $data = [
            'order' => $this->order,
            'items' => $orderItems,
            'express' => $orderExpress,
            'dispatch_type' => 'express',
        ];
        \think\Hook::listen('order_dispatch_after', $data);
        return $express;
    }

    // 手动发货
    private function doByInput($params)
    {
        $orderItems = $this->getDispatchOrderItems($params, 'express');

        $express = $params['express'] ?? null;
        if (empty($express['name']) || empty($express['code']) || empty($express['no']) || strpos($express['no'], '=') !== false) {
            error_stop('请输入正确的快递信息');
        }
        return [$orderItems, $express];
    }

    // API发货
    private function doByApi($params)
    {
        $orderItems = $this->getDispatchOrderItems($params, 'express');
        $sender = $params['sender'] ?? null;
        $expressLib = new ExpressLib();

        $data = [
            'order' => $this->order,
            'sender' => $sender,
            'consignee' => $this->order->address
        ];
        $express = $expressLib->eOrder($data, $orderItems);
        return [$orderItems, $express];
    }

    // 上传发货模板发货 TODO: 如果发货单比较多，循环更新可能会比较慢，考虑解析完模版信息以后，把数据返回前端，再次执行批量发货流程
    private function doByUpload($params)
    {
        $orderItems = $this->getDispatchOrderItems($params, 'express');

        $express = $params['express'] ?? null;
        if (empty($express['name']) || empty($express['code']) || empty($express['no'])) {
            error_stop('请输入正确的快递信息');
        }
        return [$orderItems, $express];
    }

    // 获取可发货的订单商品
    public function getDispatchOrderItems($params = null, $dispatch_type = 'express')
    {
        $orderItemIds = $params['order_item_ids'] ?? [];
        $whereCanDispatch['order_id'] = $this->order->id;
        $whereCanDispatch['dispatch_status'] = OrderItem::DISPATCH_STATUS_NOSEND;
        $whereCanDispatch['aftersale_status'] = ['<>', OrderItem::AFTERSALE_STATUS_ING];
        $whereCanDispatch['refund_status'] = OrderItem::REFUND_STATUS_NOREFUND;
        $whereCanDispatch['dispatch_type'] = $dispatch_type;
        
        if (empty($orderItemIds)) {
            $orderItems = OrderItem::where($whereCanDispatch)->select();
        } else {
            $orderItems = OrderItem::where('id', 'in', $orderItemIds)->where($whereCanDispatch)->select();

            if (count($orderItems) !== count($orderItemIds)) {
                error_stop('选中商品暂不能发货');
            }
        }

        if (!$orderItems) {
            error_stop('该订单无可发货商品');
        }
        return $orderItems;
    }



    /**
     * 取消发货
     *
     */
    public function cancel($params)
    {
        $admin = auth_user();

        $order_express_id = $params['order_express_id'] ?? 0;
        $orderExpress = OrderExpress::where('id', $order_express_id)->find();
        if (!$orderExpress) {
            error_stop('未找到发货单');
        }
        // 1.检测是不是用api发的 有些快递不支持取消接口 所以不判断了，统一手动取消
        // if ($orderExpress->method === 'api') {
        //     // TODO: 走取消运单接口
        //     $expressLib = new ExpressLib();

        //     $data = [
        //         'express_no' => $orderExpress['express_no'],
        //         'express_code' => $orderExpress['express_code'],
        //         'order_code' => $orderExpress['ext']['Order']['OrderCode']
        //     ];

        //     $express = $expressLib->cancel($data);
        // }
        // 2. 变更发货状态
        $orderItems = OrderItem::where([
            'order_id' => $this->order->id,
            'order_express_id' => $orderExpress->id
        ])->where('dispatch_type', 'express')->select();


        foreach ($orderItems as $orderItem) {
            $orderItem->order_express_id = 0;
            $orderItem->dispatch_status = OrderItem::DISPATCH_STATUS_NOSEND;
            $orderItem->save();
            OrderAction::add($this->order, null, $admin, 'admin', "已取消发货");
        }
        // 删除发货单
        $orderExpress->delete();
        return true;
    }

    /**
     * 修改发货信息
     *
     */
    public function change($params)
    {
        $admin = auth_user();

        $order_express_id = $params['order_express_id'] ?? 0;

        $orderExpress = OrderExpress::where('id', $order_express_id)->find();
        if (!$orderExpress) {
            error_stop('未找到发货单');
        }
        // 1.1 检测是不是用api发的 如果是则提醒取消运单再重新走发货流程 此时什么都不用做
        if ($orderExpress->method === 'api') {
            error_stop('该发货单已被推送第三方平台，请取消后重新发货');
        }
        // 1.2 如果不是则手动变更运单信息（快递公司、运单号）
        $express = $params['express'] ?? null;
        if (empty($express['name']) || empty($express['code']) || empty($express['no']) || strpos($express['no'], '=') !== false) {
            error_stop('请输入正确的快递信息');
        }

        $orderExpress->save([
            'express_name' => $express['name'],
            'express_code' => $express['code'],
            'express_no' => $express['no'],
            'method' => 'input'
        ]);

        OrderAction::add($this->order, null, $admin, 'admin', "变更发货信息");
        $this->subscribeExpressInfo($orderExpress);
        // 修改发货信息
        $data = [
            'order' => $this->order,
            'express' => $orderExpress,
            'dispatch_type' => 'express',
        ];
        \think\Hook::listen('order_dispatch_change', $data);
        return $express;
    }

    // 解析批量发货信息,筛选出能发货的订单
    public function multiple($params)  
    {
        // 上传发货模板
        if (!empty($params['file'])) {
            $express = $params['express'];
            $file = $params['file']->getPathname();
            $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
            $PHPExcel = $reader->load($file);
            $currentSheet = $PHPExcel->getSheet(0);  //读取文件中的第一个工作表
            $allRow = $currentSheet->getHighestRow(); //取得一共有多少行
            if ($allRow <= 2) {
                error_stop('您的发货列表为空');
            }

            $orderExpressMap = [];
            $orderId = 0;
            $orderSn = "";
            for ($currentRow = 2; $currentRow <= $allRow - 1; $currentRow++) {

                $orderId = $currentSheet->getCellByColumnAndRow(1, $currentRow)->getValue() ?? $orderId;
                $orderSn = $currentSheet->getCellByColumnAndRow(2, $currentRow)->getValue() ?? $orderSn;

                $orderItemId = $currentSheet->getCellByColumnAndRow(8, $currentRow)->getValue();
                if (empty($orderItemId)) {
                    error_stop("发货单格式不正确");
                }
                $orderExpressNo = $currentSheet->getCellByColumnAndRow(15, $currentRow)->getValue();
                if (empty($orderExpressNo)) {
                    error_stop("请填写 订单ID-{$orderId} 的运单号");
                }
                $orderExpressMap["$orderId.$orderSn"][$orderExpressNo][] = $orderItemId;
            }

            $list = [];
            foreach ($orderExpressMap as $orderFlag => $orderExpress) {
                foreach ($orderExpress as $expressNo => $orderItemIds) {
                    $order = explode('.', $orderFlag);
                    $list[] = [
                        'order_id' => $order[0],
                        'order_sn' => $order[1],
                        'order_item_ids' => $orderItemIds,
                        'express' => [
                            'name' => $express['name'],
                            'code' => $express['code'],
                            'no' => $expressNo
                        ]
                    ];
                }
            }
            return $list;
        } else {
            $list = [];
            $orderIds = $params['order_ids'] ?? [];
            if (empty($orderIds)) {
                error_stop('请选择发货订单');
            }
            foreach ($orderIds as $orderId) {
                $list[] = [
                    'order_id' => $orderId,
                    'order_sn' => Order::where('id', $orderId)->value('order_sn'),
                    'order_item_ids' => $this->getDispatchOrderItemIds($orderId)
                ];
            }
            return $list;
        }
    }

    // 获取可发货的订单商品
    private function getDispatchOrderItemIds($orderId)
    {
        $whereCanDispatch = [
            'order_id' => $orderId,
            'dispatch_status' => OrderItem::DISPATCH_STATUS_NOSEND,
            'aftersale_status' => ['neq', OrderItem::AFTERSALE_STATUS_ING],
            'refund_status' => OrderItem::REFUND_STATUS_NOREFUND,
            'dispatch_type' => 'express'
        ];

        $orderItems = OrderItem::where($whereCanDispatch)->column('id');

        return $orderItems;
    }

    // 订阅物流追踪
    private function subscribeExpressInfo($orderExpress)
    {
        try {
            $expressLib = new ExpressLib();

            $address = $this->order->address;

            $a = $expressLib->subscribe([
                'express_code' => $orderExpress['express_code'],
                'express_no' => $orderExpress['express_no'],
                'mobile' => $address['mobile'] ?: '',
            ]);
        } catch (\Exception $e) {
            // Nothing TODO
            return;
        }
    }



    /**
     * 手动发货
     *
     * @param array $params
     * @return void
     */
    public function customDispatch($params)
    {
        $admin = auth_admin();

        $custom_type = $params['custom_type'] ?? 'text';
        $custom_content = $params['custom_content'] ?? ($custom_type == 'text' ? '' : []);

        if ($this->order->status !== Order::STATUS_PAID && !$this->order->isOffline($this->order)) {
            error_stop("该订单{$this->order->status_text},不能发货");
        }

        if ($this->order->apply_refund_status === Order::APPLY_REFUND_STATUS_APPLY) {
            error_stop("该订单已申请退款,暂不能发货");
        }

        // 获取手动发货的 items
        $orderItems = $this->getDispatchOrderItems($params, 'custom');

        $customExt = [      // 手动发货信息
            'dispatch_content_type' => $custom_type,
            'dispatch_content' => $custom_content 
        ];

        // 修改订单商品发货状态
        foreach ($orderItems as $orderItem) {
            $orderItem->dispatch_status = OrderItem::DISPATCH_STATUS_SENDED;
            $orderItem->ext = array_merge($orderItem->ext, $customExt, ['send_time' => time()]);    // item 发货时间
            $orderItem->save();
            OrderAction::add($this->order, $orderItem, $admin, 'admin', "商品{$orderItem->goods_title}已发货");
        }
        // 订单发货后
        $data = [
            'order' => $this->order,
            'items' => $orderItems,
            'express' => null,
            'dispatch_type' => 'custom',
        ];
        \think\Hook::listen('order_dispatch_after', $data);
    }


    /**
     * 拼团完成时触发检测自动发货
     *
     * @return bool
     */
    public function grouponCheckDispatchAndSend()
    {
        $this->systemCheckAutoSend();

        return true;
    }


    /**
     * 普通商品自动发货
     *
     * @return bool
     */
    public function checkDispatchAndSend()
    {
        // 拼团不自动发货，等成团完成才发货
        $orderExt = $this->order['ext'];
        $buy_type = ($orderExt && isset($orderExt['buy_type'])) ? $orderExt['buy_type'] : '';
        if ($this->order['activity_type'] && strpos($this->order['activity_type'], 'groupon') !== false && $buy_type == 'groupon') {
            return true;        // 这里不对拼团的订单进行自动发货，等拼团成功在检测
        }

        // 检测需要自动发货的 item
        $this->systemCheckAutoSend();

        return true;
    }



    /**
     * 系统检测自动发货
     */
    private function systemCheckAutoSend()
    {
        $autosendItems = [];

        // 判断订单是否有需要发货的商品，并进行自动发货（autosend）
        foreach ($this->order->items as $key => $item) {
            // 判断不是未发货状态，或者退款完成，continue
            if (
                $item['dispatch_status'] == OrderItem::DISPATCH_STATUS_NOSEND
                && $item['aftersale_status'] != OrderItem::AFTERSALE_STATUS_ING
                && $item['refund_status'] == OrderItem::REFUND_STATUS_NOREFUND
            ) {
                // 订单可以发货
                switch ($item['dispatch_type']) {
                    case 'autosend':
                        // 自动发货
                        $autosendItems[] = $item;
                    }
            }
        }
        
        if ($autosendItems) {
            $this->autoSendItems($autosendItems, ['oper_type' => 'system']);
        }
    }


    /**
     * 当前订单需要自动发货的所有商品
     *
     * @param object|array $items
     * @return void
     */
    private function autoSendItems($items)
    {
        foreach ($items as $item) {
            $autosendExt = $this->getAutosendContent($item);

            $item->dispatch_status = OrderItem::DISPATCH_STATUS_SENDED;
            $item->ext = array_merge($item->ext, $autosendExt, ['send_time' => time()]);    // item 发货时间
            $item->save();
            OrderAction::add($this->order, $item, null, 'system', "商品{$item->goods_title}已发货");
        }

        $data = [
            'order' => $this->order,
            'items' => $items,
            'express' => null,
            'dispatch_type' => 'custom',
        ];

        // 发货后事件，消息通知
        \think\Hook::listen('order_dispatch_after', $data);
    }


    /**
     * 获取商品的自动发货模板数据
     *
     * @param object|array $item
     * @return array
     */
    private function getAutosendContent($item) 
    {
        // 获取配送模板
        $result = [];

        $dispatch = DispatchModel::with([$item['dispatch_type']])->show()->where('type', $item['dispatch_type'])->where('id', $item['dispatch_id'])->find();
        if ($dispatch && $dispatch->autosend) {
            $autosend = $dispatch->autosend;
            if (in_array($autosend['type'], ['text', 'params'])) {
                $result['dispatch_content_type'] = $autosend['type'];
                $result['dispatch_content'] = $autosend['content'];
            }
        }

        return $result;
    }
}
