import traceback
from random import uniform, randint

from bs4 import BeautifulSoup
from loguru import logger

from configs import configs
from .devtools import Browser
from .spider import Spider

PLACEHOLDER = ".   "
_paper_config = configs['paper']


async def list_books(detail):
    try:
        async with Spider() as spider:
            await spider.login(**configs['user'])
            courses = await spider.get_courses()

            for cr in courses:
                if detail:
                    hint = f'{cr["courseName"]}({cr["teacherName"]})'
                else:
                    hint = cr['courseName']
                logger.info(f'[课程信息] | {hint}')

                books = await spider.get_books(cr["courseId"])
                for book in books:
                    if detail:
                        hint = f'[{cr["courseId"]}-{book["bookId"]}] {book["bookName"]}({book["percent"]}%)'
                    else:
                        hint = f'{book["bookName"]}'
                    logger.info(f'[书籍信息] | {hint}')
    except Exception:
        logger.warning(f'[读取信息] | 读取信息出错:\n{traceback.format_exc()}')


async def _random(spider, paper_id):  # 随机的分数和学习时长
    try:
        paper = BeautifulSoup((await spider.get_paper(paper_id))['paperData'], 'lxml-xml')
        questions = paper.select('element[knowledge]:has(> question_type)')
        if not questions:
            return 100, 5

        total = 0
        score, time = 0, 0
        for q in questions:
            q_type = int(q.select_one('question_type').text)
            q_score = float(q.select_one('question_score').text)
            total += q_score

            ranges = _paper_config['random-score']
            if q_type <= len(ranges) and ranges[q_type - 1] is not None:
                r = ranges[q_type - 1]
                if not isinstance(r, list):
                    r = [r, r]
                score += q_score * uniform(*r)
            else:
                q_no = q.select_one('question_no').text
                logger.warning(f'[任务点信息] | 题[{q_no}] 未知题型')
                if _paper_config['defaults'] == 'pause':
                    score += float(input('[任务点信息] | 请手动输入该题得分 [0-1]:'))
                else:  # defaults
                    score += q_score * uniform(*_paper_config['defaults'])

            time += randint(*_paper_config['random-time'])

        return int(100 * score / total), time
    except Exception:
        logger.warning(f'[处理随机数据] | 处理随机数据出错:\n{traceback.format_exc()}')


async def _flash(course_id, book_id, spider):
    try:
        async def dfs(node, depth=0):
            task = node.task
            logger.info(f"[刷任务点] | {PLACEHOLDER * depth} {task['name']}")
            if _paper_config['skip-finished'] and task['unitStudyPercent'] == 100:
                logger.info(f"[刷任务点] | {PLACEHOLDER * depth} 跳过")
                return
            if 'paperId' in task:  # 如果有任务则提交
                chapter_id = task['chapterId']
                task_id = task['id']
                score, time = await _random(spider, task['paperId'])
                result = await page.submit(book_id, chapter_id, task_id, score, time, 100, user_id)
                if result['wasThrown'] or not result['result']['value']:
                    logger.warning(f'[刷任务点] | 任务[{task["name"]}]可能提交失败,请留意最终结果')
            for ch in node.child:
                await dfs(ch, depth + 1)

        browser = await Browser.connect()
        page = await browser.wait_for_page(r'https?://pc\.ismartin\.com.*')

        # With Spider
        await spider.login(**configs['user'])
        user_id = (await spider.user_info())['data']['uid']
        book_type = (await spider.book_info(book_id))['bookType']
        root = await spider.get_tasks(book_id, book_type, course_id)
        await dfs(root)
    except Exception:
        logger.warning(f'[刷任务点] | 刷任务点出错:\n{traceback.format_exc()}')


async def flash_by_id(identity):
    async with Spider() as spider:
        await _flash(*identity.split('-'), spider)


async def flash_current():  # 对当前课程或书籍执行刷课
    browser = await Browser.connect()
    course_id, book_id = await browser.get_current()
    async with Spider() as spider:
        if book_id:
            await _flash(course_id, book_id, spider)
        else:
            await spider.login(**configs['user'])
            books = await spider.get_books(course_id)
            for book in books:
                await _flash(course_id, book['bookId'], spider)


async def flash_all():
    async with Spider() as spider:
        await spider.login(**configs['user'])
        courses = await spider.get_courses()
        for course in courses:
            course_id = course['courseId']
            books = await spider.get_books(course_id)
            for book in books:
                await _flash(course_id, book['bookId'], spider)