<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);

namespace app\timer\service\groupon;

use app\common\library\helper;
use app\timer\library\Tools;
use app\timer\model\Order as OrderModel;
use app\timer\model\groupon\Task as TaskModel;
use app\timer\model\groupon\Setting as SettingModel;
use app\common\service\Order as OrderService;
use app\common\service\order\Refund as RefundService;
use app\common\enum\order\OrderStatus as OrderStatusEnum;
use app\common\service\BaseService;

/**
 * 服务类:拼团拼单任务
 * Class Task
 * @package app\timer\service\groupon
 */
class Task extends BaseService
{
    /**
     * 拼单失败事件
     * @param int $storeId
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function taskFailEvent(int $storeId): bool
    {
        // 获取已失效的拼单ID集
        $model = new TaskModel;
        $taskIds = $model->getFailTaskIds($storeId);
        // 记录日志
        Tools::taskLogs('GrouponTask', 'taskFailEvent', [
            'title' => '拼单失败事件',
            'storeId' => $storeId,
            'taskIds' => helper::jsonEncode($taskIds),
        ]);
        // 将拼团失败的订单退款处理
        $this->refundFailOrder($storeId, $taskIds);
        // 标记拼单失效状态
        return empty($taskIds) || $model->setStatusFail($taskIds);
    }

    /**
     * 拼单模拟成团事件
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function taskMockEvent(int $storeId)
    {
        // 获取模拟成团的拼单
        $model = new TaskModel;
        $taskList = $model->getMockTaskList($storeId);
        // 拼单任务ID集
        $taskIds = helper::getArrayColumn($taskList, 'task_id');
        // 批量将拼单模拟成团
        if (!empty($taskIds)) {
            foreach ($taskList as $task) {
                $model->mockTask($task, $storeId);
            }
        }
        // 记录日志
        Tools::taskLogs('GrouponTask', 'taskMockEvent', [
            'title' => '拼单模拟成团事件',
            'robotIds' => helper::jsonEncode($taskIds),
        ]);
    }

    /**
     * 拼单完成事件
     * @param int $storeId
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function taskCompleteEvent(int $storeId): bool
    {
        // 获取已完成的拼单ID集
        $model = new TaskModel;
        $taskIds = $model->getCompleteTaskIds($storeId);
        // 记录日志
        Tools::taskLogs('GrouponTask', 'taskCompleteEvent', [
            'title' => '拼单完成事件',
            'storeId' => $storeId,
            'taskIds' => helper::jsonEncode($taskIds),
        ]);
        // 将已完成拼单的未付款订单取消
        $this->cancelCompleteOrder($storeId, $taskIds);
        return true;
    }

    /**
     * 将拼团失败的订单退款处理
     * @param int $storeId
     * @param array $taskIds
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function refundFailOrder(int $storeId, array $taskIds)
    {
        // 是否开启拼单失败自动退款
        if (!SettingModel::taskFailAutoRefund($storeId)) {
            return;
        }
        // 查询拼团拼单失败的已付款订单
        $model = new OrderModel;
        $list = $model->getListByGrouponTaskFail($storeId, $taskIds);
        // 订单ID集
        $orderIds = helper::getArrayColumn($list, 'order_id');
        // 用于记录退款失败的订单ID
        $invalidOrderIds = [];
        if (!empty($orderIds)) {
            foreach ($list as $order) {
                try {
                    // 执行订单退款并关闭
                    (new RefundService)->handle($order) && OrderService::cancelEvent($order);
                } catch (\Throwable $e) {
                    $invalidOrderIds[] = $order['order_id'];
                }
            }
            // 批量更新订单状态为已取消
            $result = array_diff($orderIds, $invalidOrderIds);
            !empty($result) && $model->onBatchUpdate($result, ['order_status' => OrderStatusEnum::CANCELLED]);
        }
        // 记录日志
        Tools::taskLogs('GrouponTask', 'refundFailOrder', [
            'title' => '将到期的拼团订单退款处理',
            'storeId' => $storeId,
            'orderIds' => helper::jsonEncode($orderIds),
            'invalidOrderIds' => helper::jsonEncode($invalidOrderIds),
        ]);
    }

    /**
     * 将已完成拼单的未付款订单取消
     * @param int $storeId
     * @param array $taskIds
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function cancelCompleteOrder(int $storeId, array $taskIds)
    {
        // 查询拼团拼单已完成的未付款订单
        $model = new OrderModel;
        $list = $model->getListByGrouponTaskComplete($storeId, $taskIds);
        // 订单ID集
        $orderIds = helper::getArrayColumn($list, 'order_id');
        // 用于记录退款失败的订单ID
        if (!empty($orderIds)) {
            foreach ($list as $order) {
                OrderService::cancelEvent($order);
            }
            // 批量更新订单状态为已取消
            $model->onBatchUpdate($orderIds, ['order_status' => OrderStatusEnum::CANCELLED]);
        }
        // 记录日志
        Tools::taskLogs('GrouponTask', 'cancelCompleteOrder', [
            'title' => '将已完成拼单的未付款订单取消',
            'storeId' => $storeId,
            'orderIds' => helper::jsonEncode($orderIds),
        ]);
    }
}