import random
import asyncio
from typing import Dict, List

from gsuid_core.logger import logger
from gsuid_core.segment import MessageSegment
from gsuid_core.utils.api.mys_api import mys_api
from gsuid_core.utils.error_reply import get_error
from gsuid_core.utils.database.models import GsUser
from gsuid_core.utils.plugins_config.gs_config import core_plugins_config
from gsuid_core.utils.boardcast.models import BoardCastMsg, BoardCastMsgDict

GAME_NAME_MAP = {
    'gs': '原神',
    'sr': '崩铁',
    'zzz': '绝区零',
}


async def sign_error(uid: str, retcode: int, game_name: str = 'gs') -> str:
    sign_title = f'[{game_name}] [签到]'
    error_msg = get_error(retcode)
    logger.warning(
        f'{sign_title} {uid} 出错, 错误码{retcode}, 错误消息{error_msg}!'
    )
    if retcode == 10001 or retcode == -100:
        ck = await GsUser.get_user_cookie_by_uid(uid, game_name)
        if ck:
            await GsUser.update_data_by_uid_without_bot_id(
                uid, game_name, status='error'
            )
    return f'[{game_name}] 签到失败!{error_msg}'


async def sign_in(uid: str, game_name: str = 'gs') -> str:
    _gn = GAME_NAME_MAP.get(game_name, '未知游戏')
    sign_title = f'[{_gn}] [签到]'
    logger.info(f'{sign_title} {uid} 开始执行签到')
    is_os = mys_api.check_os(uid, game_name)
    # 获得签到信息
    sign_info = await mys_api.get_sign_info(uid, game_name)
    # 初步校验数据
    if isinstance(sign_info, int):
        return await sign_error(uid, sign_info, game_name)
    # 检测是否已签到
    if sign_info['is_sign']:
        logger.info(f'{sign_title} {uid} 该用户今日已签到,跳过...')
        day_of_month = int(sign_info['today'].split('-')[-1])
        signed_count = int(sign_info['total_sign_day'])
        sign_missed = day_of_month - signed_count
        return f'✅[{_gn}] UID{uid}今日已签到！\n🚨本月漏签次数：{sign_missed}'

    # 实际进行签到
    Header = {}
    for index in range(4):
        # 进行一次签到
        sign_data = await mys_api.mys_sign(uid, game_name, header=Header)
        # 检测数据
        if isinstance(sign_data, int):
            return await sign_error(uid, sign_data, game_name)
        if 'risk_code' in sign_data:
            # 出现校验码
            if sign_data['risk_code'] in [375, 5001]:
                if core_plugins_config.get_config('CaptchaPass').data:
                    gt = sign_data['gt']
                    ch = sign_data['challenge']
                    vl, ch = await mys_api._pass(gt, ch, Header)
                    if vl:
                        delay = 1
                        Header['x-rpc-challenge'] = ch
                        Header['x-rpc-validate'] = vl
                        Header['x-rpc-seccode'] = f'{vl}|jordan'
                        logger.info(
                            f'{sign_title} {uid} 已获取验证码, 等待时间{delay}秒'
                        )
                        await asyncio.sleep(delay)
                    else:
                        delay = 605 + random.randint(1, 120)
                        logger.info(
                            f'{sign_title} {uid} 未获取验证码,等待{delay}秒后重试...'
                        )
                        await asyncio.sleep(delay)
                    continue
                else:
                    logger.info(
                        '配置文件暂未开启[跳过无感验证],跳过本次签到任务...'
                    )
                return '签到失败...出现验证码!'
            # 成功签到!
            else:
                if index == 0:
                    logger.info(f'{sign_title} {uid} 该用户无校验码!')
                else:
                    logger.info(
                        f'{sign_title} [无感验证] {uid} 该用户重试 {index} 次验证成功!'
                    )
                break
        elif is_os and (sign_data['code'] == 'ok'):
            # 国际服签到无risk_code字段
            logger.info(f'[国际服签到] {uid} 签到成功!')
            break
        else:
            # 重试超过阈值
            logger.warning('{sign_title} 超过请求阈值...')
            vl_hint = '❌签到失败...出现验证码!'
            return f'{vl_hint}'
    # 签到失败
    else:
        im = '❌签到失败!'
        logger.warning(f'{sign_title} UID{uid} 签到失败, 结果: {im}')
        return im
    # 获取签到列表
    sign_list = await mys_api.get_sign_list(uid, game_name)
    new_sign_info = await mys_api.get_sign_info(uid, game_name)

    if isinstance(sign_list, int):
        return await sign_error(uid, sign_list, game_name)
    elif isinstance(new_sign_info, int):
        return await sign_error(uid, new_sign_info, game_name)

    # 获取签到奖励物品，拿旧的总签到天数 + 1 为新的签到天数，再 -1 即为今日奖励物品的下标
    getitem = sign_list['awards'][int(sign_info['total_sign_day']) + 1 - 1]
    get_im = f'📝本次签到获得{getitem["name"]}x{getitem["cnt"]}'
    day_of_month = int(new_sign_info['today'].split('-')[-1])
    signed_count = int(new_sign_info['total_sign_day'])
    sign_missed = day_of_month - signed_count
    if new_sign_info['is_sign']:
        mes_im = '✅签到成功'
    else:
        mes_im = '❌签到失败...'
        sign_missed -= 1
    sign_missed = sign_info.get('sign_cnt_missed') or sign_missed
    im = f'{mes_im}!\n{get_im}\n🚨本月漏签次数：{sign_missed}'
    logger.info(
        f'✅ {sign_title} UID{uid} 签到完成!\n📝结果: {mes_im}\n🚨漏签次数: {sign_missed}'
    )
    return im


async def single_daily_sign(
    bot_id: str,
    uid: str,
    gid: str,
    qid: str,
    game_name: str,
    private_msgs: Dict,
    group_msgs: Dict,
):
    im = await sign_in(uid, game_name)
    if gid == 'on':
        if qid not in private_msgs:
            private_msgs[qid] = []
        private_msgs[qid].append(
            {'bot_id': bot_id, 'uid': uid, 'msg': [MessageSegment.text(im)]}
        )
    else:
        # 向群消息推送列表添加这个群
        if gid not in group_msgs:
            group_msgs[gid] = {
                'bot_id': bot_id,
                'success': 0,
                'failed': 0,
                'push_message': [],
            }
        if im.startswith(('签到失败', '网络有点忙', 'OK', 'ok')):
            group_msgs[gid]['failed'] += 1
            group_msgs[gid]['push_message'].extend(
                [
                    MessageSegment.text('\n'),
                    MessageSegment.at(qid),
                    MessageSegment.text('\n'),
                    MessageSegment.text(im),
                ]
            )
        else:
            group_msgs[gid]['success'] += 1


async def daily_sign(game_name: str):
    tasks = []
    private_msgs = {}
    group_msgs = {}
    _user_list: List[GsUser] = await GsUser.get_all_user()
    uid_list = []
    user_list: List[GsUser] = []
    for user in _user_list:
        _uid = getattr(
            user,
            f'{game_name}_uid' if game_name and game_name != 'gs' else 'uid',
        )
        _switch = getattr(
            user,
            (
                f'{game_name}_sign_switch'
                if game_name and game_name != 'gs'
                else 'sign_switch'
            ),
        )
        if _switch != 'off' and not user.status and _uid:
            uid_list.append(_uid)
            user_list.append(user)

    logger.info(f'[{game_name}] [全部重签] [UID列表] {uid_list}')
    for user in user_list:
        tasks.append(
            single_daily_sign(
                user.bot_id,
                getattr(
                    user,
                    (
                        f'{game_name}_uid'
                        if game_name and game_name != 'gs'
                        else 'uid'
                    ),
                ),
                getattr(
                    user,
                    (
                        f'{game_name}_sign_switch'
                        if game_name and game_name != 'gs'
                        else 'sign_switch'
                    ),
                ),
                user.user_id,
                game_name,
                private_msgs,
                group_msgs,
            )
        )
        if len(tasks) >= 1:
            await asyncio.gather(*tasks)
            delay = 30 + random.randint(3, 35)
            logger.info(
                f'[{game_name}] [签到] 已签到{len(tasks)}个用户, 等待{delay}秒进行下一次签到'
            )
            tasks.clear()
            await asyncio.sleep(delay)
    await asyncio.gather(*tasks)
    tasks.clear()

    # 转为广播消息
    private_msg_dict: Dict[str, List[BoardCastMsg]] = {}
    group_msg_dict: Dict[str, BoardCastMsg] = {}
    for qid in private_msgs:
        msgs = []
        for i in private_msgs[qid]:
            msgs.extend(i['msg'])

        if qid not in private_msg_dict:
            private_msg_dict[qid] = []

        private_msg_dict[qid].append(
            {
                'bot_id': private_msgs[qid][0]['bot_id'],
                'messages': msgs,
            }
        )

    for gid in group_msgs:
        success = group_msgs[gid]['success']
        faild = group_msgs[gid]['failed']
        _gn = GAME_NAME_MAP.get(game_name, '未知游戏')
        title = f'✅{_gn}今日自动签到已完成！\n📝本群共签到成功{success}人，共签到失败{faild}人。'
        messages = [MessageSegment.text(title)]
        if group_msgs[gid]['push_message']:
            messages.append(MessageSegment.text('\n'))
            messages.extend(group_msgs[gid]['push_message'])
        group_msg_dict[gid] = {
            'bot_id': group_msgs[gid]['bot_id'],
            'messages': messages,
        }

    result: BoardCastMsgDict = {
        'private_msg_dict': private_msg_dict,
        'group_msg_dict': group_msg_dict,
    }

    logger.info(result)
    return result
