<?php
namespace Base\Service;

use Base\Facade\Request;
use Base\Tool\GameResource;
use Base\Repository\TestingResourceRepository;
use Base\Repository\SpendRepository;
use Think\Model;

class TestingResourceService
{
    public $repository;

    public function __construct()
    {
        $this->repository = new TestingResourceRepository();
    }

    public function verify($batch, $verifyAdminId = 0)
    {
        if ($batch['verify_status'] != 0) {
            throw new \Exception('审核状态异常');
        }

        $batchData = [];
        $batchData['verify_time'] = time();
        $batchData['update_time'] = time();
        
        $gameIds = $this->repository->getHadSettingGameIds();
        if (!in_array($batch['game_id'], $gameIds)) {
            $batchData['verify_status'] = 2;
            $batchData['verify_remark'] = '该游戏暂不支持资源申请!';
            M('testing_resource_batch', 'tab_')->where(['id' => $batch['id']])->save($batchData);
            throw new \Exception('该游戏发放功能暂未实现');
        }

        $batchData['verify_status'] = 1;
        $batchData['verify_remark'] = '审核成功';
        $batchData['verify_admin_id'] = $verifyAdminId;
        M('testing_resource_batch', 'tab_')->where(['id' => $batch['id']])->save($batchData);
    }

    public function verifyRefuse($batch, $remark = '审核拒绝', $verifyAdminId = 0)
    {
        if ($batch['verify_status'] != 0) {
            throw new \Exception('审核状态异常');
        }

        $batchData = [];
        $batchData['verify_time'] = time();
        $batchData['update_time'] = time();
        $batchData['verify_status'] = 2;
        $batchData['verify_remark'] = $remark;
        $batchData['verify_admin_id'] = $verifyAdminId;
        M('testing_resource_batch', 'tab_')->where(['id' => $batch['id']])->save($batchData);
    }

    public function provideRefuse($batch, $remark = '发放失败')
    {
        if ($batch['verify_status'] != 1) {
            throw new \Exception('该申请未审核通过');
        }
        if ($batch['provide_status'] != 0) {
            throw new \Exception('发放状态异常');
        }

        M('testing_resource_order', 'tab_')
            ->where(['batch_id' => $batch['id']])
            ->save([
                'provide_status' => 2,
                'provide_time' => time(),
            ]);

        M('testing_resource_batch', 'tab_')
            ->where(['id' => $batch['id']])
            ->save([
                'provide_status' => 2,
                'provide_time' => time(),
                'update_time' => time()
            ]);
    }

    public function provide($batch)
    {
        if ($batch['verify_status'] != 1) {
            throw new \Exception('该申请未审核通过');
        }

        if ($batch['provide_status'] != 0) {
            throw new \Exception('发放状态异常');
        }

        $gameSetting = $this->repository->getGameSettingByGameId($batch['game_id']);
        if (is_null($gameSetting)) {
            throw new \Exception('该游戏不支持发放测试资源');
        }
        $role = M('user_play_info', 'tab_')
            ->field(['id', 'role_id', 'user_id', 'promote_id', 'user_account', 'sdk_version', 'server_id'])
            ->where(['game_id' => $batch['game_id'], 'role_id' => $batch['role_id']])
            ->find();
        $orders = M('testing_resource_order', 'tab_')
            ->where(['batch_id' => $batch['id']])
            ->select();

        $game = M('game', 'tab_')->field(['id', 'sdk_version'])->where(['id' => $batch['game_id']])->find();

        $hasError = false;
        $provideAmount = 0;
        foreach ($orders as $order) {
            $orderData = [];
            if ($gameSetting['has_itf'] == 1) {
                $gameResource = new GameResource($game);
                $result = $gameResource->apply($order, $role);
                $orderData = [
                    'result' => json_encode($result),
                ];
                if (!$result['status']) {
                    $hasError = true;
                    $orderData['provide_status'] = 2;
                } else {
                    $orderData['provide_status'] = 1;
                }
            } else {
                $orderData['provide_status'] = 1;
            }
            $provideAmount += $order['amount'];
            $orderData['provide_time'] = time();
            M('testing_resource_order', 'tab_')
                ->where(['id' => $order['id']])
                ->save($orderData);
        }
        
        $batchData = [];
        if ($hasError) {
            $batchData['provide_status'] = 2;
        } else {
            $batchData['provide_status'] = 1;
        }
        $batchData['provide_time'] = time();
        $batchData['provide_amount'] = $provideAmount;
        $batchData['update_time'] = time();
        M('testing_resource_batch', 'tab_')
            ->where(['id' => $batch['id']])
            ->save($batchData);
    }

    public function getRemainQuota($role, $bindRole = null, $gameSetting = null)
    {
        if (is_null($gameSetting)) {
            $gameSetting = $this->repository->getGameSettingByGameId($role['game_id']);
        }

        if (is_null($gameSetting)) {
            throw new \Exception('游戏未设置测试资源');
        }

        $totalQuota = $role['testing_other_quota'] + ($gameSetting['base_quota'] ?? 0);
        if (!is_null($bindRole)) {
            $bindTime = $bindRole['binding_time'] ?? 0;

            $spendMap = [
                'game_id' => $role['game_id'],
                'game_player_id' => $bindRole['role_id'],
                'pay_status' => 1,
                'pay_time' => ['egt', strtotime(date('Y-m-d 00:00:00', $bindTime))]
            ];
            $spendRepository = new SpendRepository();
            $spendMap = $spendRepository->withIsCheck($spendMap);

            $spendQuota += M('spend', 'tab_')
                ->where($spendMap)
                ->group('game_id,game_player_id')
                ->sum('pay_amount');
            $totalQuota += round($gameSetting['rate'] / 100 * $spendQuota, 2);
        }
        $providedQuota = M('testing_resource_batch', 'tab_')
            ->where(['provide_status' => [in, [1, 2]], 'game_id' => $role['game_id'], 'role_id' => $role['role_id']])
            ->sum('provide_amount');
        $providingQuota = M('testing_resource_batch', 'tab_')
            ->where(['verify_status' => [in, [0, 1]], 'provide_status' => 0, 'game_id' => $role['game_id'], 'role_id' => $role['role_id']])
            ->sum('apply_amount');
        return round(floatval($totalQuota) - floatval($providedQuota) - floatval($providingQuota), 2);
    }

    public function addTestingUsers($accounts, $promote = null)
    {
        // 测试账号是否自动审核
        $isAutoVerify = true;
        $verifyStatus = 0;
        $verifyTime = 0;
        if ($isAutoVerify) {
            $verifyStatus = 1;
            $verifyTime = time();
        }

        $accounts = array_unique($accounts);
        $existAccounts = M('testing_user', 'tab_')->where(['user_account' => ['in', $accounts]])->getField('user_account', true);
        $existAccounts = $existAccounts ?? [];
        $existCount = count($existAccounts);
        $newAccounts = array_diff($accounts, $existAccounts);
        $errorCount = 0;
        $successCount = 0;
        if (count($newAccounts)) {

            $strCondition = '1=1';
            if ($promote) {
                $promoteService = new PromoteService();
                $strCondition .=  ' and promote_id in (' . $promoteService->subInSql($promote) . ')';
            }

            $users = M('user', 'tab_')->field(['id', 'account'])->where(['account' => ['in', $newAccounts], '_string' => $strCondition])->select();
            $errorAccounts = array_diff($newAccounts, array_column($users, 'account'));
            $errorCount = count($errorAccounts);
            foreach ($users as $user) {
                if (in_array($user['account'], $errorAccounts)) {
                    continue;
                }
                $data = [
                    'user_id' => $user['id'],
                    'user_account' => $user['account'],
                    'status' => 1,
                    'verify_status' => $verifyStatus,
                    'verify_time' => $verifyTime,
                    'create_time' => time(),
                    'update_time' => time(),
                ];
                M('testing_user', 'tab_')->add($data);
                $successCount ++;
            }
        }
        return [
            'errorCount' => $errorCount,
            'successCount' => $successCount,
            'existCount' => $existCount,
        ];
    }

    public function saveGameSetting($params)
    {
        $gameId = $params['base_game_id'] ?? 0;
        $baseQuota = $params['base_quota'] ?? 0;
        $rate = $params['rate'] ?? 0;

        if ($gameId == 0) {
            throw new \Exception('请选择游戏');
        }

        $data = [
            'base_game_id' => $gameId,
            'base_quota' => $baseQuota,
            'rate' => $rate,
        ];
            
        $setting = M('testing_game_setting', 'tab_')->where(['base_game_id' => $gameId])->find();
        if ($setting) {
            $data['update_time'] = time();
            M('testing_game_setting', 'tab_')->where(['base_game_id' => $gameId])->save($data);
        } else {
            $data['create_time'] = time();
            $data['update_time'] = time();
            M('testing_game_setting', 'tab_')->add($data);
        }
    }

    public function bindRole($params, $promote = null)
    {
        $gameId = $params['game_id'] ?? 0;
        $testingRoleId = $params['testing_role_id'] ?? '';
        $bindRoleId = $params['bind_role_id'] ?? '';
        
        $testingGameRoleId = $this->repository->getGameRoleId($gameId, $testingRoleId);
        $bindGameRoleId = $this->repository->getGameRoleId($gameId, $bindRoleId);

        $testingRole = M('user_play_info', 'tab_')
            ->field(['id', 'role_id', 'user_id', 'game_id', 'promote_id'])
            ->where(['game_role_id' => $testingGameRoleId])
            ->find();
        if (is_null($testingRole)) {
            throw new \Exception('测试账号角色不存在');
        }

        $testingUser = M('testing_user', 'tab_')->where(['user_id' => $testingRole['user_id']])->find();
        if (is_null($testingUser)) {
            throw new \Exception('测试账号不存在');
        }

        if ($testingUser['verify_status'] != 1) {
            throw new \Exception('测试账号未审核通过');
        }

        if (!in_array($testingUser['status'], [1, 2])) {
            throw new \Exception('测试账号已禁用');
        }

        $promoteService = new PromoteService();
        $testPromote = M('promote', 'tab_')->field(['id', 'chain'])->where(['id' => $testingRole['promote_id']])->find();
        if (is_null($testPromote) || ($promote && !$promoteService->isSubOrSelf($testPromote, $promote))) {
            throw new \Exception('测试角色所属推广员异常');
        }

        $bindRole = M('user_play_info', 'tab_')
            ->field(['id', 'role_id', 'user_id', 'promote_id'])
            ->where(['game_role_id' => $bindGameRoleId])
            ->find();
        if (is_null($bindRole)) {
            throw new \Exception('玩家角色不存在');
        }

        $bindPromote = M('promote', 'tab_')->field(['id', 'chain'])->where(['id' => $bindRole['promote_id']])->find();
        if (is_null($bindPromote) || ($promote && !$promoteService->isSubOrSelf($bindPromote, $promote))) {
            throw new \Exception('玩家账号所属推广员异常');
        }

        /* if ($testPromote['id'] != $bindPromote['id']) {
            throw new \Exception('玩家账号与测试账号非同一推广员');
        } */

        $bindIsTesting = M('testing_user', 'tab_')->where(['user_id' => $bindRole['user_id']])->find();
        if ($bindIsTesting) {
            throw new \Exception('该玩家账号为测试账号,无法绑定');
        }

        $existBind = M('testing_binding', 'tab_')->field(['id'])->where(['game_id' => $gameId, 'bind_role_id' => $bindRoleId])->find();
        if ($existBind) {
            throw new \Exception('该玩家角色已被绑定');
        }

        $testExistBind = M('testing_binding', 'tab_')->field(['id'])->where(['game_id' => $gameId, 'role_id' => $testingRoleId])->find();
        if ($testExistBind) {
            throw new \Exception('该测试账号角色已绑定有角色');
        }

        $status = M('testing_binding', 'tab_')->add([
            'game_id' => $testingRole['game_id'],
            'user_id' => $testingRole['user_id'],
            'role_id' => $testingRole['role_id'],
            'bind_user_id' => $bindRole['user_id'],
            'bind_role_id' => $bindRole['role_id'],
            'create_time' => time(),
            'update_time' => time()
        ]);
        if (!$status) {
            throw new \Exception('绑定角色异常');
        }
    }

    public function unbindRole($bindingId)
    {
        return M('testing_binding', 'tab_')->where(['id' => $bindingId])->delete();
    }

    public function apply($params, $promote = null, $adminId = 0)
    {
        $gameId = $params['game_id'] ?? 0;
        $roleId = $params['role_id'] ?? '';
        $serverId = $params['server_id'] ?? 0;
        $userAccount = $params['user_account'] ?? '';
        $records = $params['records'] ?? [];
        
        if ($promote && $promote['level'] > 2) {
            throw new \Exception('权限不足');
        }

        $game = M('game', 'tab_')->where(['id' => $gameId])->find();
        $resources = $this->getResources($game);

        $gameSetting = $this->repository->getGameSettingByGameId($gameId);
        if (is_null($gameSetting)) {
            throw new \Exception('该游戏不支持发放测试资源');
        }

        $binding = M('testing_binding', 'tab_')->where(['game_id' => $gameId, 'role_id' => $roleId])->find();
        /* if (is_null($binding)) {
            throw new \Exception('该角色未绑定玩家角色');
        } */

        $user = M('user', 'tab_')->field(['id', 'promote_id'])->where(['account' => $userAccount])->find();
        if (is_null($user)) {
            throw new \Exception('玩家账号不存在');
        }
        $testingUser = M('testing_user', 'tab_')->where(['user_id' => $user['id']])->find();
        if (is_null($testingUser)) {
            throw new \Exception('测试账号不存在');
        }
        if ($testingUser['verify_status'] != 1) {
            throw new \Exception('测试账号未审核通过');
        }

        if (!in_array($testingUser['status'], [1, 2])) {
            throw new \Exception('测试账号已禁用');
        }
        $server = M('server', 'tab_')->field(['id', 'server_name', 'server_id'])->where(['id' => $serverId])->find();
        if (is_null($server)) {
            throw new \Exception('区服不存在');
        }

        $promoteService = new PromoteService();

        $role = M('user_play_info', 'tab_')
            ->field(['id', 'role_id', 'promote_id', 'game_id', 'testing_other_quota'])
            ->where(['user_id' => $user['id'], 'game_id' => $gameId, 'server_id' => $server['server_id'], 'role_id' => $roleId])
            ->find();
        if (is_null($role)) {
            throw new \Exception('角色不存在');
        }

        $otherRoleBatch = M('testing_resource_batch', 'tab_')
            ->where([
                'user_id' => $user['id'],
                'game_id' => $gameId,
                'server_id' => $server['server_id'],
                'role_id' => ['neq', $roleId],
                'verify_status' => ['in', [0, 1]],
            ])
            ->find();
        if ($otherRoleBatch) {
            throw new \Exception('每个账号同区服只能申请一个角色');
        }

        $testPromote = M('promote', 'tab_')->field(['id', 'chain'])->where(['id' => $role['promote_id']])->find();
        if (is_null($testPromote) || ($promote && !$promoteService->isSubOrSelf($testPromote, $promote))) {
            throw new \Exception('测试角色所属推广员异常');
        }

        $bindingRole = null;
        if ($binding) {
            $bindingRole = M('user_play_info', 'tab_')
                ->field(['id', 'role_id', 'user_id', 'promote_id', 'game_id'])
                ->where(['game_id' => $gameId, 'role_id' => $binding['bind_role_id']])
                ->find();
            if (is_null($bindingRole)) {
                throw new \Exception('绑定玩家角色不存在');
            }
            $bindingRole['binding_time'] = $binding['create_time'];
            $bindPromote = M('promote', 'tab_')->field(['id', 'chain'])->where(['id' => $bindingRole['promote_id']])->find();
            if (is_null($bindPromote) || ($promote && !$promoteService->isSubOrSelf($bindPromote, $promote))) {
                throw new \Exception('绑定角色所属推广员异常');
            }
            /* if ($testPromote['id'] != $bindPromote['id']) {
                throw new \Exception('测试账号与玩家账号所属推广员不同');
            } */
        }

        $hasItf = ($gameSetting['has_itf'] == 1);
        $amount = 0;
        if ($hasItf) {
            foreach ($records as $key => $record) {
                if (isset($resources[$record['resource_id']])) {
                    $value = $resources[$record['resource_id']]['amount'];
                    $records[$key]['value'] = $value;
                    $records[$key]['resource_name'] = $resources[$record['resource_id']]['name'];
                    $amount += $record['num'] * $value;
                } else {
                    throw new \Exception('含有资源内容不存在');
                }
                /**
                 * @todo 游戏猫只能每个资源数量只能为1
                 */
                if ($record['num'] != 1) {
                    throw new \Exception('该游戏每次申请单项资源数量只能为1');
                }
            }
        } else {
            foreach ($records as $key => $record) {
                if (empty($record['amount'])) {
                    throw new \Exception('请输入资源价值');
                }
                if (empty($record['remark'])) {
                    throw new \Exception('请输入资源备注');
                }
                $amount += $record['amount'];
            }
        }
        
        $remainQuota = $this->getRemainQuota($role, $bindingRole, $gameSetting);
        if ($amount > $remainQuota) {
            throw new \Exception('额度不足');
        }

        $olderBatch = M('testing_resource_batch', 'tab_')
            ->field(['id'])
            ->where(['user_id' => $testingUser['user_id'], 'game_id' => $gameId, 'verify_status' => 1])
            ->find();
        $batchNo = date('YmdHis') . substr(md5($roleId . strval(microtime(true)) . rand(0, 9999)), 8, 16);

        try {
            $model = new Model();
            $model->startTrans();

            $batch = [
                'batch_no' => $batchNo,
                'user_id' => $testingUser['user_id'],
                'game_id' => $gameId,
                'role_id' => $roleId,
                'server_id' => $serverId,
                'apply_promote_id' => $promote ? $promote['id'] : 0,
                'apply_admin_id' => $adminId,
                'apply_amount' => $amount,
                'provide_status' => 0,
                'verify_status' => 0,
                'auto_verify' => $gameSetting['has_itf'] == 1 && $olderBatch ? 1 : 0,
                'create_time' => time(),
                'update_time' => time(),
            ];
            $batchId = M('testing_resource_batch', 'tab_')->add($batch);
            $i = 1;
            foreach ($records as $record) {
                $orderNo = $batchNo . '_' . $i;
                $order = [
                    'batch_id' => $batchId,
                    'order_no' => $orderNo,
                    'ref_id' => $record['resource_id'] ?? '',
                    'ref_name' => isset($record['resource_name']) ? $record['resource_name'] : ($record['remark'] ?? ''),
                    'ref_amount' => isset($record['amount']) ? $record['amount'] : $record['value'],
                    'num' => $record['num'] ?? 1,
                    'amount' => isset($record['amount']) ? $record['amount'] : ($record['num'] * $record['value']),
                    'remark' => $record['remark'],
                ];
                M('testing_resource_order', 'tab_')->add($order);
            }
            $model->commit();
        } catch (\Exception $e) {
            $model->rollback();
            throw new \Exception('系统异常' . $e->getMessage());
        }
    }

    public function getResourceTypes($game)
    {
        $gameSetting = $this->repository->getGameSettingByGameId($game['id']);
        if ($gameSetting['has_itf'] == 0) {
            return [];
        }
        $gameResource = new GameResource($game);
        return $gameResource->getResourceTypes();
    }

    public function getResources($game, $typeId = null)
    {
        $gameSetting = $this->repository->getGameSettingByGameId($game['id']);
        if ($gameSetting['has_itf'] == 0) {
            return [];
        }
        $gameResource = new GameResource($game);
        return $gameResource->getResources($typeId);
    }

    public function getHasItfGameIds()
    {
        $gameSettings = $this->repository->getGameSettings();
        $baseGameIds = [];
        foreach ($gameSettings as $gameSetting) {
            if ($gameSetting['has_itf'] == 1) {
                $baseGameIds[] = $gameSetting['base_game_id'];
            }
        }
        $baseGames = [];
        if (count($baseGameIds) > 0) {
           $baseGames = M('base_game', 'tab_')->where(['id' => ['in', $baseGameIds]])->select();
        }
        if (empty($baseGames)) {
            return [];
        } else {
            return array_merge(array_column($baseGames, 'android_game_id'), array_column($baseGames, 'ios_game_id'));
        }
    }

    public function verifyTestingUser($userIds, $verifyStatus)
    {
        if (count($userIds) == 0) {
            throw new \Exception('请选择要审核的测试账号');
        }

        if (!in_array($verifyStatus, [1, 2])) {
            throw new \Exception('状态值异常');
        }

        $testingUsers = M('testing_user', 'tab_')->where(['verify_status' => 0, 'user_id' => ['in', $userIds]])->get();
        if (count($testingUsers) == 0) {
            throw new \Exception('含有非待审核的测试账号');
        }

        M('testing_user', 'tab_')->where(['user_id' => ['in', $userIds]])->save([
            'status' => $verifyStatus
        ]);
    }

    public function freezeTestingUser($userId)
    {
        $testingUser = M('testing_user', 'tab_')->where(['user_id' => $userId])->find();
        if (is_null($testingUser)) {
            throw new \Exception('测试账号不存在');
        }
        M('testing_user', 'tab_')->where(['user_id' => $userId])->save([
            'status' => 3
        ]);
    }

    public function unfreezeTestingUser($userId)
    {
        $testingUser = M('testing_user', 'tab_')->where(['user_id' => $userId])->find();
        if (is_null($testingUser)) {
            throw new \Exception('测试账号不存在');
        }
        M('testing_user', 'tab_')->where(['user_id' => $userId])->save([
            'status' => 1
        ]);
    }

    public function deleteTestingUser($userId)
    {
        $testingUser = M('testing_user', 'tab_')->where(['user_id' => $userId])->find();
        if (is_null($testingUser)) {
            throw new \Exception('测试账号不存在');
        }
        if ($testingUser['verify_status'] != 2) {
            throw new \Exception('只有审核拒绝的测试账号才能删除');
        }

        M('testing_user', 'tab_')->where(['user_id' => $userId])->delete();
    }
}