<?php
/**
 * Created by PhpStorm.
 * User: pengfei@yidian-inc.com
 * Date: 2021/9/3 2:23 下午
 */

use App\Base\Job;
use Api\PhpServices\Idgen\Idgen;
use App\Models\marketing\mysql\ColonelDistributorColonel;
use App\Models\marketing\mysql\ColonelDistributorConfig;
use App\Models\marketing\mysql\ColonelDistributorInviteOrderNum;
use App\Models\marketing\mysql\ColonelDistributorPayInfo;
use App\Exception\custom\InterfaceException;
use Api\PhpUtils\Http\HttpUtil;
use App\Models\marketing\mysql\Marketing;
use App\Models\user\mysql\UserWechatBind;
use App\Services\marketing\PindanActivityColonelConfigService;
use Api\PhpUtils\Log\JobLog;
use App\Services\marketing\ColonelService;

class ColonelorderController extends Job
{
    const REWARD_UNIT = 100;  // 奖励单位: 分
    const INVITE_NEW_USER_REWARD = 3 * self::REWARD_UNIT; // 邀请新用户奖励
    const DEFAULT_USER_BATCH_SIZE = 100; // 批量处理数据条数
    const ACTIVITY_OFFLINE_BALANCE = 50 * self::REWARD_UNIT; // 活动余额下线阈值

    public $colonelConfigList; // 活动配置
    public $settlementDate;    // 活动结算日
    public $startTime;         // 活动结算日-开始时间
    public $endTime;           // 活动结算日-结束时间

    /**
     * Notes: 初始化-读取配置
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/3 4:13 下午
     */
    public function init()
    {
        parent::init();
        $this->loadTimeConfig();
        $this->colonelConfigList = $this->getColonelConfig($this->settlementDate);
    }

    /**
     * Notes: 计算奖励脚本
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/3 4:05 下午
     * @throws InterfaceException
     */
    public function indexAction()
    {
        $this->loggerInfo('start');
        if ($userIdList = ColonelDistributorColonel::getColonelUserIds()) {
            $userIdList = array_chunk($userIdList, self::DEFAULT_USER_BATCH_SIZE);
            $colonelPayInfoData = [];
            foreach ($userIdList as $userIds) {
                $this->getInviteOrderData($userIds, $colonelPayInfoData);   // 完成目标单数
                $this->getInviteNewUserData($userIds, $colonelPayInfoData); // 邀请新用户奖励
            }
            if (!empty($colonelPayInfoData)) {
                try {
                    $this->loggerInfo('colonelPayInfoCount=' . count($colonelPayInfoData));
                    $this->handleMarketingBalance($colonelPayInfoData);
                    $colonelPayInfoData = $this->getFormatPayInfoData($colonelPayInfoData);
                    $this->handleSavePayInfo($colonelPayInfoData);
                    $this->loggerInfo('success');
                } catch (Exception $e) {
                    $this->loggerError('error=' . $e->getMessage());
                }
            }
        }
        $this->loggerInfo('end');
    }

    /**
     * Notes: 保存奖励信息
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/7 10:40 上午
     * @param $colonelPayInfoData
     * @throws Exception
     */
    private function handleSavePayInfo($colonelPayInfoData)
    {
        try {
            ColonelDistributorPayInfo::beginTransaction();
            if (!$this->addColonelDistributorPayInfo($colonelPayInfoData)) {
                throw new Exception(sprintf("写入错误参数 %s", json_encode($colonelPayInfoData)));
            }
            if (!ColonelDistributorPayInfo::commit()) {
                throw new Exception(sprintf("事务提交失败 %s", json_encode($colonelPayInfoData)));
            }
        } catch (Exception $e) {
            ColonelDistributorPayInfo::rollback();
            throw new Exception($e->getMessage());
        }
    }

    /**
     * Notes: 获取新用户奖励
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/3 4:47 下午
     * @param $userIds
     * @param $colonelPayInfoData
     * @throws InterfaceException
     */
    private function getInviteNewUserData($userIds, &$colonelPayInfoData)
    {
        if ($inviteNewUserList = $this->getInviteNewUserList($userIds, $this->startTime, $this->endTime)) {
            $userNickList = $this->getUserList(array_column($inviteNewUserList, 'user_id'));
            foreach ($inviteNewUserList as $newUser) {
                $colonelPayInfoData[] = [
                    'date'             => $this->settlementDate,
                    'type'             => ColonelDistributorPayInfo::TYPE_NEW_USER,
                    'reward'           => self::INVITE_NEW_USER_REWARD,
                    'finish_num'       => 1,
                    'invite_user_id'   => $newUser['user_id'],
                    'invite_user_nick' => empty($userNickList[$newUser['user_id']]['user_nick']) ? '' : $userNickList[$newUser['user_id']]['user_nick'],
                    'colonel_user_id'  => $newUser['inviter_user_id'],
                ];
            }
        }
    }

    /**
     * Notes: 获取完成目标单数奖励
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/3 4:47 下午
     * @param $userIds
     * @param $colonelPayInfoData
     */
    private function getInviteOrderData($userIds, &$colonelPayInfoData)
    {
        if (!empty($this->colonelConfigList)) {
            $inviteOrderNumList = $this->getInviteOrderNum($userIds, $this->settlementDate);
            foreach ($inviteOrderNumList as $orderNum) {
                foreach ($this->colonelConfigList as $config) {
                    if ($orderNum['num'] >= $config['assess_order_num']) {
                        $colonelPayInfoData[] = [
                            'date'             => $this->settlementDate,
                            'type'             => ColonelDistributorPayInfo::TYPE_FINISH_TARGET,
                            'reward'           => $config['reward_amount'] * self::REWARD_UNIT,
                            'finish_num'       => $config['assess_order_num'],
                            'invite_user_id'   => 0,
                            'invite_user_nick' => '',
                            'colonel_user_id'  => $orderNum['colonel_user_id'],
                        ];
                    }
                }
            }
        }
    }

    /**
     * 团长任务配置
     * @param $settlementDate
     * @return array
     */
    private function getColonelConfig($settlementDate): array
    {
        $config = ColonelDistributorConfig::getRecord([
            'date[<=]' => $settlementDate,
            'type'     => ColonelDistributorConfig::TYPE_COLONEL,
            'ORDER'    => ['date' => 'DESC'],
            'LIMIT'    => 1
        ]);
        $configData = [];
        if (!empty($config['data'])) {
            $configData = json_decode($config['data'], true);
        }
        return $configData;
    }

    /**
     * 获取order num
     * @param $colonelUserIds
     * @param $date
     * @return array
     */
    private function getInviteOrderNum($colonelUserIds, $date): array
    {
        return ColonelDistributorInviteOrderNum::getRecords(
            [
                'colonel_user_id' => $colonelUserIds,
                'date'            => $date,
            ],
            ['colonel_user_id', 'num']
        );
    }

    /**
     * Notes: 获取有效新用户信息
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/3 4:03 下午
     * @param $userIds
     * @param $startTime
     * @param $endTime
     * @return array
     * @throws InterfaceException
     */
    private function getInviteNewUserList($userIds, $startTime, $endTime): array
    {
        $url = config('interface', 'coupon.background.wx_invite_relation_list_by_user_ids');
        if (empty($url)) {
            throw new InterfaceException(['cus' => 0]);
        }
        $res = HttpUtil::get($url,
            ['user_ids' => $userIds, 'start_time' => $startTime, 'end_time' => $endTime]);
        if (!empty($res['response']['result'])) {
            return array_values(array_column($res['response']['result'], null, 'user_id'));
        }
        return [];
    }

    /**
     * Notes: 获取pay_info数据
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/7 10:34 上午
     * @param $data
     * @return array
     * @throws Exception
     */
    private function getFormatPayInfoData($data): array
    {
        $count = count($data);
        $httpParams = [
            [
                'type'   => 'goods',
                'number' => 00,
                'count'  => $count
            ]
        ];
        $res = Idgen::get(appConfig('idgen.partner'), appConfig('idgen.key'), [], $httpParams);
        $ids = $res['id_datetime']['goods'] ?? [];
        if ($count > count($ids)) {
            throw new Exception('请求idgen服务失败，' . ['req' => $httpParams, 'res' => $res]);
        }
        foreach ($data as $key => $item) {
            $data[$key]['pay_info_trade_id'] = $ids[$key];
        }
        return $data;
    }

    /**
     * Notes: 用户信息，获取昵称
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/3 4:09 下午
     * @param $userIds
     * @return array
     */
    private function getUserList($userIds): array
    {
        $list = UserWechatBind::select(['user_id', 'user_nick'], ['user_id' => $userIds], []);
        return array_column((array)$list, null, 'user_id');
    }

    /**
     * Notes: 写入数据
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/3 4:10 下午
     * @param $data
     * @return bool
     */
    private function addColonelDistributorPayInfo($data): bool
    {
        return (int)ColonelDistributorPayInfo::save($data);
    }

    /**
     * Notes: 获取团长分销资余额
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/9 6:19 下午
     * @return array
     * @throws Exception
     */
    private function getMarketingCapitalPoolBalance(): array
    {
        if (!$url = config('interface', 'coupon.capitalpool.detail')) {
            throw new Exception('没有capitalpool配置');
        }
        if (!$marketing = ColonelService::getMarketingInfo()) {
            throw new Exception('没有获取到资金池');
        }
        $httpParams = [
            'capital_pool_id' => $marketing['capital_pool_id']
        ];
        $response = HttpUtil::post($url, $httpParams, 100000, 3);
        $this->loggerInfo("url=$url,request=" . json_encode($httpParams) . ";response=" . json_encode($response));
        if (!isset($response['response']['result']['capital_pool_total'])) {
            throw new Exception('没有获取到资金池信息,' . ['req' => $httpParams, 'res' => $response]);
        }
        $result = $response['response']['result'];
        $balance = ($result['capital_pool_total'] - $result['capital_pool_lock'] - $result['capital_pool_used']);
        return [
            'marketing_id' => $marketing['marketing_id'],
            'balance'      => $balance
        ];
    }

    /**
     * Notes: 检测资金余额，是否下线活动
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/9 6:29 下午
     * @param $colonelPayInfoData
     * @throws Exception
     */
    private function handleMarketingBalance($colonelPayInfoData)
    {
        $totalReward = array_sum(array_column($colonelPayInfoData, 'reward'));
        $marketing = $this->getMarketingCapitalPoolBalance();
        $diffBalance = $marketing['balance'] - $totalReward;
        if (0 >= $diffBalance) {
            throw new Exception('资金池可用余额不足');
        }
        // 达到活动下线条件
        if (self::ACTIVITY_OFFLINE_BALANCE >= $diffBalance) {
            Marketing::updateRecord(
                ['online_status' => Marketing::ONLINE_STATUS_GUANBI],
                ['marketing_id' => $marketing['marketing_id']]
            );
        }
    }

    /**
     * Notes: 加载配置
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/8 7:43 下午
     */
    private function loadTimeConfig()
    {
        // 如果传入时间-使用指定时间
        $params = $this->getRequest()->getParams();
        if (empty($params['date']) || !strtotime($params['date'])) {
            $timeRange = PindanActivityColonelConfigService::getSettlementTimeRange();
            $this->settlementDate = $timeRange['date'];
            $this->startTime = $timeRange['start_time'];
            $this->endTime = $timeRange['end_time'];
        } else {
            $hour = PindanActivityColonelConfigService::ACTIVITY_DEFAULT_HOUR;
            $this->settlementDate = $params['date'];
            $this->startTime = "{$params['date']} $hour:00:00";
            $this->endTime = date('Y-m-d H:i:s', strtotime($this->startTime . ' +1 day'));
        }
    }

    /**
     * Notes: 记录 info 日志
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/3 4:10 下午
     * @param $log
     */
    private function loggerInfo($log)
    {
        JobLog::getInstance()->info('colonel_distributor_order', $log)->output();
    }

    /**
     * Notes: 记录 error 日志
     * User: pengfei@yidian-inc.com
     * Date: 2021/9/3 4:10 下午
     * @param $log
     */
    private function loggerError($log)
    {
        JobLog::getInstance()->error('colonel_distributor_order', $log, null, 'bp-server@yidian-inc.com')->output();
    }
}
