<?php
namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use think\Db;
use app\admin\model\shopro\commission\Order as CommissionOrderModel;
use app\admin\model\shopro\commission\Reward as RewardModel;
use addons\shopro\service\commission\Order as OrderService;
use addons\shopro\service\commission\Reward as RewardService;
use addons\shopro\service\commission\Agent as AgentService;

/**
 * 补漏分销商分佣脚本
 *
 * 遍历已完成/已支付的订单，检查分销佣金是否遗漏，补全数据：
 * 1. 对于完全没有分佣订单记录的商品，模拟"订单支付成功"流程
 *    创建 commission_order + commission_reward（含佣金流水日志）
 * 2. 对于已支付订单，补全代理绑定、分销商创建等支付后逻辑
 * 3. 对于已有分佣记录但佣金状态为"未结算"的：
 *    - 已完成订单: 使用 admin 事件结算（绕过 reward_event 匹配限制）
 *    - 已支付订单: 使用 paid 事件尝试结算（遵守系统配置）
 *
 * 命令：php think shopro:fix-missed-commission
 *      php think shopro:fix-missed-commission --order_id=123         （指定订单）
 *      php think shopro:fix-missed-commission --status=paid            （只处理已支付订单）
 *      php think shopro:fix-missed-commission --status=all             （处理已支付+已完成）
 *
 * 使用场景：
 *   - 历史订单漏掉分销商分佣时，一次性补填数据
 *   - 支付后脚本异常导致佣金记录/代理绑定/分销商创建遗漏
 *   - 可重复执行，已结算的记录不会重复打款
 */
class FixMissedCommission extends Command
{
    /**
     * 控制台输出对象
     * @var Output
     */
    protected $output = null;

    /**
     * 分页大小
     */
    const PAGE_SIZE = 100;

    /**
     * 配置命令信息
     */
    protected function configure()
    {
        $this->setName('shopro:fix-missed-commission')
             ->setDescription('补漏分销商分佣：遍历已完成/已支付订单，补充遗漏的分销佣金记录并结算')
             ->addOption('order_id', null, Option::VALUE_OPTIONAL, '指定订单ID（只处理该订单）', null)
             ->addOption('status', null, Option::VALUE_OPTIONAL, '订单状态: paid(已支付) / completed(已完成) / all(全部)', 'completed');
    }

    /**
     * 自定义日志记录方法
     *
     * @param string $level 日志级别: info/warning-warn/error
     * @param string $message 日志内容
     */
    protected function customLog($level, $message)
    {
        $timestamp = date('Y-m-d H:i:s');
        $formattedMessage = "[{$timestamp}] [{$level}] {$message}";

        if ($this->output) {
            switch ($level) {
                case 'error':
                    $this->output->writeln("<error>{$formattedMessage}</error>");
                    break;
                case 'warn':
                    $this->output->writeln("<comment>{$formattedMessage}</comment>");
                    break;
                default:
                    $this->output->writeln("<info>{$formattedMessage}</info>");
                    break;
            }
        }

        custom_log($message, 0, 'fix_missed_commission', $level);
    }

    /**
     * 命令执行入口
     *
     * @param Input $input
     * @param Output $output
     */
    protected function execute(Input $input, Output $output)
    {
        $this->output = $output;

        // 指定订单ID（可选参数）
        $specifiedOrderId = $input->getOption('order_id');

        // 订单状态过滤
        $statusFilter = $input->getOption('status');
        if (!in_array($statusFilter, ['paid', 'completed', 'all'])) {
            $statusFilter = 'completed';
        }
        $statusName = ['paid' => '已支付', 'completed' => '已完成', 'all' => '已支付+已完成'][$statusFilter];

        $this->customLog('info', '========== 开始补漏分销商分佣 ==========');
        $this->customLog('info', "订单状态过滤: {$statusName}");
        if ($specifiedOrderId) {
            $this->customLog('info', "指定订单模式: 仅处理订单[{$specifiedOrderId}]");
        }

        try {
            $page = 1;
            $totalOrders = 0;
            $totalCreated = 0;       // 新创建的分销订单数
            $totalSettled = 0;       // 新结算的奖励数
            $totalSkipped = 0;       // 已结算跳过的
            $totalNoAction = 0;      // 无需任何操作的订单（无商品/无分销/无待结算）

            // 详情记录：用于最后汇总输出
            $createdDetails = [];    // 新建分销订单: "订单ID[order_sn] → commission_order_id=X"
            $settledDetails = [];    // 拨款结算: "订单ID[order_sn] → commission_order_id=X"
            $skippedDetails = [];    // 已结算跳过: "订单ID[order_sn] → commission_order_id=X (状态)"
            $noActionDetails = [];   // 无需处理: "订单ID[order_sn] 原因"

            while (true) {
                // 分页查询已支付/已完成的订单（排除积分商品订单 + 已软删除订单）
                $query = Db::name('shopro_order')
                    ->where('type', '<>', 'score')
                    ->whereNull('deletetime')
                    ->field('id, user_id, order_sn, deduct_score, status')
                    ->order('id', 'asc');

                // 按状态过滤
                if ($statusFilter === 'all') {
                    $query->whereIn('status', ['paid', 'completed']);
                } else {
                    $query->where('status', $statusFilter);
                }

                if ($specifiedOrderId) {
                    $query->where('id', $specifiedOrderId);
                } else {
                    $query->page($page, self::PAGE_SIZE);
                }

                $orders = $query->select();

                if (empty($orders)) {
                    if ($specifiedOrderId) {
                        $this->customLog('error', "订单[{$specifiedOrderId}]不存在或不满足当前状态条件（状态需为{$statusName}，且未软删除、非积分商品订单）");
                    } else {
                        $this->customLog('info', "第{$page}页无数据，遍历结束");
                    }
                    break;
                }

                $pageTotal = count($orders);
                $totalOrders += $pageTotal;
                $this->customLog('info', "第{$page}页: 获取 {$pageTotal} 个{$statusName}订单");

                foreach ($orders as $order) {
                    $orderId = $order['id'];
                    $orderUserId = $order['user_id'];
                    $orderSn = $order['order_sn'] ?? '';
                    $orderStatus = $order['status'] ?? '';
                    $isPaidOrder = ($orderStatus === 'paid');
                    $deductScore = isset($order['deduct_score']) ? intval($order['deduct_score']) : 0;

                    // ===== 已支付订单：补全支付后的代理绑定/分销商创建流程 =====
                    if ($isPaidOrder) {
                        try {
                            $agentService = new AgentService($orderUserId);

                            // 绑定用户关系（上级代理绑定）
                            $bindResult = $agentService->bindUserRelation('pay');
                            if ($bindResult) {
                                $this->customLog('info', "订单[{$orderId}][{$orderSn}] ✓ 支付后代理绑定成功");
                            } else {
                                $this->customLog('info', "订单[{$orderId}][{$orderSn}] - 代理绑定跳过（已有上级或不满足绑定条件）");
                            }

                            // 创建分销商（满足条件则自动创建）
                            $agentStatus = $agentService->createNewAgent();
                            $agentStatusMap = [
                                'normal'   => '已创建(正常)',
                                'pending'  => '已创建(待审核)',
                                'needinfo' => '需补充资料',
                                'reject'   => '已拒绝',
                                'freeze'   => '已冻结',
                                'forbidden'=> '已禁用',
                            ];
                            $agentStatusText = $agentStatusMap[$agentStatus] ?? ($agentStatus === null ? '不满足条件' : "状态[{$agentStatus}]");
                            $this->customLog('info', "订单[{$orderId}][{$orderSn}] 分销商创建: {$agentStatusText}");

                            // 异步升级任务（已创建或已有分销商身份时触发）
                            if ($agentStatus !== null) {
                                $agentService->createAsyncAgentUpgrade();
                            }
                        } catch (\Exception $e) {
                            $this->customLog('warn', "订单[{$orderId}][{$orderSn}] 代理绑定/创建异常: " . $e->getMessage());
                        }
                    }

                    // 获取订单下所有未退款的商品
                    $items = Db::name('shopro_order_item')
                        ->where('order_id', $orderId)
                        ->where('refund_status', 0)  // 未申请退款
                        ->field('id, order_id, goods_id, goods_sku_price_id, pay_fee, goods_price, goods_num, goods_title, ext')
                        ->select();

                    if (empty($items)) {
                        $totalNoAction++;
                        $noActionDetails[] = "订单[{$orderId}][{$orderSn}] 原因: 无未退款商品";
                        $this->customLog('warn', "订单[{$orderId}][{$orderSn}]没有未退款商品，跳过（无操作）");
                        continue;
                    }

                    $statusTag = $isPaidOrder ? '[已支付]' : '[已完成]';
                    $this->customLog('info', "━━━ {$statusTag}订单[{$orderId}][{$orderSn}]开始处理 ━━━ 商品数:" . count($items) . " 用户ID:{$orderUserId}" . ($deductScore > 0 ? " 积分抵扣:{$deductScore}" : ""));

                    // 积分抵扣部分需按比例从佣金基数中扣除
                    $scoreDeductAmount = $deductScore > 0 ? round($deductScore / 100, 2) : 0;
                    $totalItemsPayFee = 0;
                    if ($scoreDeductAmount > 0) {
                        foreach ($items as $it) {
                            $totalItemsPayFee = bcadd($totalItemsPayFee, $it['pay_fee'], 2);
                        }
                        $this->customLog('info', "订单[{$orderId}][{$orderSn}]积分抵扣金额:{$scoreDeductAmount}元, 商品应付总额:{$totalItemsPayFee}元");
                    }

                    // 第一步：为每个缺失分佣记录的商品创建 commission_order + commission_reward（模拟支付成功流程）
                    $orderStep1Created = 0;
                    $orderStep1Skipped = 0;
                    foreach ($items as $item) {
                        $itemId = $item['id'];
                        $goodsTitle = $item['goods_title'] ?? '未知商品';

                        // 解析 ext 字段，检查 is_commission 标记
                        $ext = json_decode($item['ext'], true);
                        if (is_array($ext) && isset($ext['is_commission']) && !$ext['is_commission']) {
                            $orderStep1Skipped++;
                            $this->customLog('info', "  ├─ 商品[{$itemId}]{$goodsTitle} 标记不参与分销，跳过");
                            continue;
                        }

                        // 已存在分佣记录则跳过创建
                        $existingCommissionOrder = CommissionOrderModel::where('order_item_id', $itemId)->find();
                        if ($existingCommissionOrder) {
                            $orderStep1Skipped++;
                            $this->customLog('info', "  ├─ 商品[{$itemId}]{$goodsTitle} 已存在分佣记录[{$existingCommissionOrder->id}]，跳过");
                            continue;
                        }

                        // 补充 user_id（OrderService 需要）
                        $item['user_id'] = $orderUserId;

                        // 按比例从 pay_fee 中扣减积分抵扣金额
                        $adjustedPayFee = $item['pay_fee'];
                        if ($scoreDeductAmount > 0 && $totalItemsPayFee > 0) {
                            $itemPayFee = floatval($item['pay_fee']);
                            $totalPayFee = floatval($totalItemsPayFee);
                            $itemScoreDeduction = round($scoreDeductAmount * $itemPayFee / $totalPayFee, 2);
                            $adjustedPayFee = round($itemPayFee - $itemScoreDeduction, 2);
                            $item['pay_fee'] = $adjustedPayFee;
                            $this->customLog('info', "  ├─ 商品[{$itemId}]{$goodsTitle} 原始pay_fee:{$itemPayFee}, 积分抵扣:{$itemScoreDeduction}, 调整后:{$adjustedPayFee}");
                        }

                        try {
                            // 模拟订单支付成功后的分佣流程
                            $commission = new OrderService($item);

                            // 检查能否分销
                            if (!$commission->checkAndSetCommission()) {
                                $orderStep1Skipped++;
                                $this->customLog('warn', "  ├─ 商品[{$itemId}]{$goodsTitle} 不满足分销条件，跳过 (核算金额:{$commission->amount})");
                                continue;
                            }

                            $this->customLog('info', "  ├─ 商品[{$itemId}]{$goodsTitle} 核算金额:{$commission->amount} 开始创建分佣...");

                            // 创建分销订单
                            $commissionOrder = $commission->createCommissionOrder();
                            if (!$commissionOrder) {
                                $orderStep1Skipped++;
                                $this->customLog('warn', "  ├─ 商品[{$itemId}]{$goodsTitle} 创建分销订单失败，跳过");
                                continue;
                            }

                            // 执行佣金计划（创建 commission_reward 记录）
                            $commission->runCommissionPlan($commissionOrder);

                            // 查询创建的分佣奖励记录，输出明细
                            $rewards = RewardModel::with('agent')->where('commission_order_id', $commissionOrder->id)->select();
                            $rewardDetails = [];
                            foreach ($rewards as $reward) {
                                $agentName = $reward->agent ? ($reward->agent->nickname ?: 'ID:' . $reward->agent_id) : 'ID:' . $reward->agent_id;
                                $rewardDetails[] = "{$agentName}[{$reward->agent_id}] → {$reward->commission}元 (层级{$reward->commission_level})";
                            }
                            $rewardLog = !empty($rewardDetails) ? implode(', ', $rewardDetails) : '无奖励记录';

                        $orderStep1Created++;
                        $totalCreated++;
                        $createdDetails[] = "订单[{$orderId}][{$orderSn}] → commission_order_id={$commissionOrder->id} | 分佣: {$rewardLog}";
                        $this->customLog('info', "  ├─ 商品[{$itemId}]{$goodsTitle} ✓ 补建成功 commission_order_id={$commissionOrder->id}");
                        if (!empty($rewardDetails)) {
                            foreach ($rewardDetails as $rd) {
                                $this->customLog('info', "  │  分佣: {$rd}");
                            }
                        }

                        } catch (\Exception $e) {
                            $this->customLog('error', "  ├─ 商品[{$itemId}]{$goodsTitle} ✗ 创建分佣异常: " . $e->getMessage()."订单[{$orderId}][{$orderSn}]");
                            if (function_exists('format_log_error_custom_name')) {
                                format_log_error_custom_name($e, "[FixMissedCommission]创建分佣记录异常", '', 'fix_missed_commission');
                            }
                        }
                    }

                    // 第一步小结
                    $this->customLog('info', "  └─ 第一步完成: 新建{$orderStep1Created}条, 跳过{$orderStep1Skipped}条");

                    // 第二步：对订单下所有未结算的分销奖励执行拨款
                    $commissionOrders = CommissionOrderModel::where('order_id', $orderId)->select();
                    if (empty($commissionOrders)) {
                        $totalNoAction++;
                        $noActionDetails[] = "订单[{$orderId}][{$orderSn}] 原因: 无分销订单（无待结算/已结算分佣记录）";
                        $this->customLog('warn', "  └─ 无分销订单，跳过第二步（订单无操作）");
                        continue;
                    }

                    // 已支付订单用 paid 事件（遵守系统配置），已完成订单用 admin 事件（强制结算）
                    $settlementEvent = $isPaidOrder ? 'paid' : 'admin';
                    $this->customLog('info', "  ├─ 第二步开始: 共" . count($commissionOrders) . "条分销订单待结算 (事件:{$settlementEvent})");
                    $orderStep2Settled = 0;
                    $orderStep2Skipped = 0;

                    $rewardService = new RewardService($settlementEvent);
                    foreach ($commissionOrders as $co) {
                        $statusText = '';
                        switch ($co['commission_reward_status']) {
                            case RewardModel::COMMISSION_REWARD_STATUS_PENDING: $statusText = '待结算'; break;
                            case 1: $statusText = '已结算'; break;
                            case -1: $statusText = '已取消'; break;
                            case -2: $statusText = '已退款'; break;
                            default: $statusText = "状态[{$co['commission_reward_status']}]";
                        }

                        // 仅处理待结算状态，已结算/已退回/已取消的跳过
                        if ($co['commission_reward_status'] != RewardModel::COMMISSION_REWARD_STATUS_PENDING) {
                            $orderStep2Skipped++;
                            $totalSkipped++;
                            $skippedDetails[] = "订单[{$orderId}][{$orderSn}] → commission_order_id={$co['id']} ({$statusText})";
                            $this->customLog('info', "  │  分佣单[{$co['id']}] {$statusText}, 跳过");
                            continue;
                        }

                        try {
                            $result = $rewardService->runCommissionRewardByOrder($co);
                            if ($result) {
                                $orderStep2Settled++;
                                $totalSettled++;

                                // 查询该分佣单下的奖励记录，输出明细
                                $rewards = RewardModel::with('agent')->where('commission_order_id', $co['id'])->select();
                                $rewardDetails = [];
                                foreach ($rewards as $reward) {
                                    $agentName = $reward->agent ? ($reward->agent->nickname ?: 'ID:' . $reward->agent_id) : 'ID:' . $reward->agent_id;
                                    $rewardDetails[] = "{$agentName}[{$reward->agent_id}] → {$reward->commission}元 (层级{$reward->commission_level})";
                                }
                                $rewardLog = !empty($rewardDetails) ? implode(', ', $rewardDetails) : '无奖励记录';

                                $settledDetails[] = "订单[{$orderId}][{$orderSn}] → commission_order_id={$co['id']} | 拨款: {$rewardLog}";
                                $this->customLog('info', "  │  分佣单[{$co['id']}] ✓ 拨款成功");
                                if (!empty($rewardDetails)) {
                                    foreach ($rewardDetails as $rd) {
                                        $this->customLog('info', "  │  拨款: {$rd}");
                                    }
                                }
                            } else {
                                $this->customLog('warn', "  │  分佣单[{$co['id']}] 拨款失败（可能不满足 reward_event 条件）");
                            }
                        } catch (\Exception $e) {
                            $this->customLog('error', "  │  分佣单[{$co['id']}] ✗ 拨款异常: " . $e->getMessage());
                            if (function_exists('format_log_error_custom_name')) {
                                format_log_error_custom_name($e, "[FixMissedCommission]拨款异常", '', 'fix_missed_commission');
                            }
                        }
                    }

                    // 第二步小结
                    $this->customLog('info', "  └─ 第二步完成: 结算{$orderStep2Settled}条, 跳过{$orderStep2Skipped}条");

                    // 订单处理小结
                    $statusTag = $isPaidOrder ? '[已支付]' : '[已完成]';
                    if ($orderStep1Created > 0 || $orderStep2Settled > 0) {
                        $this->customLog('info', "━━━ {$statusTag}订单[{$orderId}][{$orderSn}]处理完成 ✓ 新建:{$orderStep1Created} 结算:{$orderStep2Settled} 跳过:{$orderStep1Skipped}+{$orderStep2Skipped} ━━━");
                    } elseif ($orderStep2Skipped > 0) {
                        $this->customLog('info', "━━━ {$statusTag}订单[{$orderId}][{$orderSn}]处理完成 - 已有分佣已结算，跳过:{$orderStep1Skipped}+{$orderStep2Skipped} ━━━");
                    } else {
                        $totalNoAction++;
                        $noActionDetails[] = "{$statusTag}订单[{$orderId}][{$orderSn}] 原因: 所有商品已有分佣记录或无分销条件";
                        $this->customLog('info', "━━━ {$statusTag}订单[{$orderId}][{$orderSn}]处理完成 - 无新操作（无需处理），跳过:{$orderStep1Skipped}+{$orderStep2Skipped} ━━━");
                    }
                }

                    // 如果本页数量少于分页大小，说明已是最后一页
                if ($pageTotal < self::PAGE_SIZE) {
                    $this->customLog('info', "第{$page}页数据不足分页大小，已是最后一页");
                    break;
                }

                $page++;
            }

            $this->customLog('info', "========== 汇总统计 ==========");
            $this->customLog('info', "共处理 {$totalOrders} 个{$statusName}订单");
            $this->customLog('info', "新建分销订单: {$totalCreated} 条, 拨款结算: {$totalSettled} 条, 已结算跳过: {$totalSkipped} 条, 无需处理: {$totalNoAction} 个订单");
            if ($statusFilter === 'paid' || $statusFilter === 'all') {
                $this->customLog('info', "提示: 已支付订单拨款使用 'paid' 事件，如系统配置需订单完成后才结算，拨款可能被跳过（符合预期）");
            }

            // 输出新建分销订单详情
            if (!empty($createdDetails)) {
                $this->customLog('info', "--- 新建分销订单({$totalCreated}条) ---");
                foreach ($createdDetails as $detail) {
                    $this->customLog('info', "  {$detail}");
                }
            }

            // 输出拨款结算详情
            if (!empty($settledDetails)) {
                $this->customLog('info', "--- 拨款结算({$totalSettled}条) ---");
                foreach ($settledDetails as $detail) {
                    $this->customLog('info', "  {$detail}");
                }
            }

            // 输出已结算跳过详情
            if (!empty($skippedDetails)) {
                $this->customLog('info', "--- 已结算跳过({$totalSkipped}条) ---");
                foreach ($skippedDetails as $detail) {
                    $this->customLog('info', "  {$detail}");
                }
            }

            // 输出无需处理订单详情
            if (!empty($noActionDetails)) {
                $this->customLog('info', "--- 无需处理订单({$totalNoAction}个) ---");
                foreach ($noActionDetails as $detail) {
                    $this->customLog('info', "  {$detail}");
                }
            }

            $this->customLog('info', '========== 补漏分销商分佣完成 ==========');

        } catch (\Exception $e) {
            $this->customLog('error', '[补漏分销商分佣失败]');
            if (function_exists('format_log_error_custom_name')) {
                format_log_error_custom_name($e, '[补漏分销商分佣失败]', '', 'fix_missed_commission');
            } else {
                $this->customLog('error', $e->getMessage() . "\n" . $e->getTraceAsString());
            }
        }
    }
}
