<?php
namespace Base\Service;

use Base\Facade\Request;
use Base\Repository\SpendRepository;

class PromoteGradeService
{
    const FOREVER_TIME = 300001;

    public static $symbols = [
        1 => '>=',
        2 => '>',
    ];

    /**
     * @config
     *      reach_level 
     *      grades
     *          - name
     *          - value
     */
    public function saveSetting($params, $promote)
    {
        $id = $params['id'] ?? 0;

        if (empty($params['base_game_id'])) {
            throw new \Exception('请选择游戏');
        }
        $monthBegin = isset($params['month_begin']) && $params['month_begin'] ? 
            date('Ym', strtotime($params['month_begin'])) : 0;
        $monthEnd = isset($params['month_end']) && $params['month_end'] ? 
            date('Ym', strtotime($params['month_end'])) : self::FOREVER_TIME;

        $setting = null;
        if ($id > 0) {
            $setting = M('promote_grade_setting', 'tab_')->where(['id' => $id])->find();
            if (is_null($setting)) {
                throw new \Exception('记录不存在');
            }
            if ($setting['company_id'] != $promote['company_id']) {
                throw new \Exception('不允许修改其他公司的配置');
            }
        } else {
            $count = $this->getRepeatRuleCount($promote['company_id'], $params['base_game_id'], $monthBegin, $monthEnd);
            if ($count > 0) {
                throw new \Exception('该游戏在相同时间段内已经设置规则');
            }
        }

        if ($monthBegin > 0 && $monthEnd > 0 && $monthBegin > $monthEnd) {
            throw new \Exception('规则截止时间不能大于规则开始时间');
        }

        $config = [];
        $config['reach_level'] = $params['level'];
        $config['grades'] = $this->sortGrades($params['grades']);
        $config['default_grade_name'] = $params['default_grade_name'];

        $data = [];
        $data['status'] = 1;
        $data['base_game_id'] = $params['base_game_id'];
        $data['month_begin'] = $monthBegin;
        $data['month_end'] = $monthEnd;
        $data['name'] = $params['name'];
        $data['config'] = json_encode($config);

        if ($setting) {
            $data['create_time'] = time();
            M('promote_grade_setting', 'tab_')->where(['id' => $id])->save($data);
        } else {
            $data['company_id'] = $promote['company_id'];
            $data['create_time'] = time();
            $data['update_time'] = time();
            M('promote_grade_setting', 'tab_')->add($data);
        }
    }

    private function sortGrades($grades)
    {
        if (count($grades) == 0) {
            return $grades;
        }   
        $values = [];
        $symbols = [];
        foreach ($grades as $key => $row) {
            $values[$key]  = $row['value'];
            $symbols[$key]  = $row['symbol'];
        }

        array_multisort($values, SORT_ASC, $symbols, SORT_ASC, $grades);
        return $grades;
    }

    public function getTimeRepeatCondition($monthBegin, $monthEnd)
    {
        return ' ((month_begin >= ' . $monthBegin . ' AND month_begin <= ' . $monthEnd . ') OR (month_begin <= ' . $monthBegin . ' AND month_end >= ' . $monthEnd 
        . ') OR (month_end >= ' . $monthBegin . ' AND month_end <= ' . $monthEnd . '))';
    }

    public function getRepeatRuleCount($companyId, $baseGameId, $monthBegin, $monthEnd)
    {
        $conditions = [
            'compnay_id' => $companyId,
            'base_game_id' => $baseGameId,
        ];
        $conditions['_string'] = $this->getTimeRepeatCondition($monthBegin, $monthEnd);
        $count = M('promote_grade_setting', 'tab_')->where($conditions)->count();
        return intval($count);
    }

    public function getCurrentSetting($promote, $baseGameId, $month)
    {
        $timeCondition = 'month_end >= ' . $month . ' and month_begin <= ' . $month;

        return M('promote_grade_setting', 'tab_')
            ->where([
                'status' => 1,
                'company_id' => $promote['company_id'],
                'base_game_id' => $baseGameId,
                '_string' => $timeCondition
            ])
            ->find();
    }

    public function searchGradeByPromotes($promotes, $params, $setting)
    {
        $config = json_decode($setting['config'], true);
        $settingLevel = $config['reach_level'];
        $month = $params['month'] ?? date('Y-m');
        $baseGameId = $params['base_game_id'] ?? 0;
        $promoteIds = array_column($promotes, 'id');
        $beginTime = strtotime($month . '-01 00:00:00');
        $endDate = date('Y-m-01 00:00:00', strtotime($month . '-01' . ' +1 month')); 
        $endTime = strtotime($endDate) - 1;

        $betweenTime = [$beginTime, $endTime];

        $userSubSql = M('user', 'tab_')
            ->field(['id'])
            ->where(['register_time' => ['between', $betweenTime], 'promote_id' => ['in', $promoteIds]])
            ->group('promote_id')
            ->select(false);
        
        $baseGame = null;
        if ($baseGameId > 0) {
            $baseGame = M('base_game', 'tab_')->where(['id' => $baseGameId])->find();
        }

        $roleMap = [
            'role_level' => ['egt', $settingLevel],
            'create_time' => ['between', $betweenTime],
            'promote_id' => ['in', $promoteIds],
            '_string' => 'user_id in (' . $userSubSql . ')'
        ];

        $spendRepository = new SpendRepository();

        $spendMap = [
            'pay_time' => ['between', $betweenTime],
            'pay_status' => 1,
            'promote_id' => ['in', $promoteIds],
            '_string' => 'user_id in (' . $userSubSql . ')'
        ];
        $spendMap = $spendRepository->withIsCheck($spendMap);

        if ($baseGame) {
            $roleMap['game_id'] = ['in', [$baseGame['android_game_id'], $baseGame['ios_game_id']]];
            $spendMap['game_id'] = ['in', [$baseGame['android_game_id'], $baseGame['ios_game_id']]];
        } else {
            $roleMap['_string'] .= ' and 1=0';
            $spendMap['_string'] .= ' and 1=0';
        }
        
        $accountItems = M('user_play_info', 'tab_')
            ->field(['promote_id', 'count(DISTINCT user_id) num'])
            ->where($roleMap)
            ->group('promote_id')
            ->select();
        $accountItems = index_by_column('promote_id', $accountItems);
        
        $amountItems = M('spend', 'tab_')
            ->field(['promote_id', 'sum(pay_amount) amount'])
            ->where($spendMap)
            ->group('promote_id')
            ->select();
        $amountItems = index_by_column('promote_id', $amountItems);

        $promoteService = new PromoteService();

        $records = [];
        foreach ($promotes as $promote) {
            $amountItem = $amountItems[$promote['id']] ?? null;
            $accountItem = $accountItems[$promote['id']] ?? null;
            $amount = $amountItem ? $amountItem['amount'] : 0;
            $num = $accountItem ? $accountItem['num'] : 0;
            $value = $num == 0 ? 0 : round($amount / $num, 2);
            $records[] = [
                'id' => $promote['id'],
                'level' => $promote['level'],
                'amount' => $amount,
                'num' => $num,
                'real_name' => hideRealName($promote['real_name']),
                'account' => $promote['account'],
                'promote_group' => $promoteService->getGroupNameByChain($promote['chain'], $promote['id']),
                'value' => $value,
                'grade_name' => $this->getGradeByValue($value, $setting),
                'current_display' => ''
            ];
        }
        return $records;
    }

    public function getGradeByValue($value, $setting)
    {
        $config = json_decode($setting['config'], true);
        $grades = $config['grades'];
        $gradeName = $config['default_grade_name'];
        foreach ($grades as $key => $grade) {
            if ($key == 0 && !$this->isBigger($value, $grade)) {
                $gradeName = $config['default_grade_name'];
                break;
            }
            $nextGrade = $grades[$key + 1] ?? null;
            if ($this->isBigger($value, $grade) && !$this->isBigger($value, $nextGrade)) {
                $gradeName = $grade['name'];
                break;
            }
        }
        return $gradeName;
    }

    private function isBigger($value, $grade)
    {
        if (is_null($grade)) {
            return false;
        }
        if ($grade['symbol'] == 1 && $value >= $grade['value']) {
            return true;
        } elseif ($grade['symbol'] == 2 && $value > $grade['value']) {
            return true;
        }
        return false;
    }
}