import re
from typing import Optional, Tuple

import sympy

from .question import register_question
from .math_tools import get_all_numbers

CN_TEXT_1 = """
第二章第一题(质数长度),你需要提出一个字数是质数的问题,使回答的长度刚好是它的下一个质数。
"""
EN_TEXT_1 = """
For the first question in chapter 2, You need to come up with a question that has a prime number of words, so the answer's length is exactly the next prime number.
"""


def _is_prime(v):
    return sympy.isprime(v)


def _next_prime(v):
    while v:
        v += 1
        if _is_prime(v):
            return v


def _cn_checker_1(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
    qs_length = len(user_text.strip())
    if not _is_prime(qs_length):
        return False, f'问题长度为{qs_length},非质数'

    answer_value = len(answer_text)
    next_prime = _next_prime(qs_length)
    if answer_value != next_prime:
        return False, f'下一个质数为{next_prime},但回答长度为{answer_value}'

    return True, None


def _en_words(text: str):
    return len(re.findall(r'\w+', text))


def _en_checker_1(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
    qs_length = _en_words(user_text.strip())
    if not _is_prime(qs_length):
        return False, f'The question has a length of {qs_length}, which is not a prime number'

    answer_value = _en_words(answer_text)
    next_prime = _next_prime(qs_length)
    if answer_value != next_prime:
        return False, f'The next prime number is {next_prime}, but the answer\'s length is {answer_value}'

    return True, None


register_question(
    {
        'cn': CN_TEXT_1,
        'en': EN_TEXT_1,
    },
    checkers={
        'cn': _cn_checker_1,
        'en': _en_checker_1,
    },
    name={'cn': '2-1 质数长度', 'en': '2-1'},
    level=2
)

CN_TEXT_2 = """
第二章第二题(越说越大),请输入一个大于一的正整数作为问题,使回答里包含至少比它大一千的数。
"""
EN_TEXT_2 = """
For the second question in chapter 2, Please enter a positive integer greater than one as a question, so that the answer contains a number that is at least one thousand more than it.
"""


def _cn_checker_2(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
    try:
        value = int(user_text.strip())
        if value <= 1:
            raise ValueError
    except (TypeError, ValueError):
        return False, f'输入内容{user_text!r},并非一个大于1的正整数'

    for value_item in get_all_numbers(answer_text):
        if value_item >= value + 1000:
            return True, f'检测到输出中数字{value_item},满足要求'

    return False, f'未在输出中检测到不少于{value + 1000}的数字'


def _en_checker_2(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
    try:
        value = int(user_text.strip())
        if value <= 1:
            raise ValueError
    except (TypeError, ValueError):
        return False, f'You entered {user_text!r}, which is not a positive integer greater than 1'

    for value_item in get_all_numbers(answer_text):
        if value_item >= value + 1000:
            return True, f'Detected the number {value_item} in the output, which meets the requirement'

    return False, f'Did not detect a number of at least {value + 1000} in the output'


register_question(
    {
        'cn': CN_TEXT_2,
        'en': EN_TEXT_2,
    },
    checkers={
        'cn': _cn_checker_2,
        'en': _en_checker_2,
    },
    name={'cn': '2-2 越说越大', 'en': '2-2'},
    level=2
)

CN_TEXT_3 = """
第二章第三题(越说越小),请输入一个大于一的正整数作为问题,使回答里包含至少10个不同的至少比它小一千的自然数。
"""
EN_TEXT_3 = """
For the third question in chapter 2, Please enter a positive integer greater than one as a question, so that the answer contains at least 10 different natural numbers, each of them at least 1000 less than the question.
"""


def _cn_checker_3(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
    try:
        value = int(user_text.strip())
        if value <= 1:
            raise ValueError
    except (TypeError, ValueError):
        return False, f'输入内容{user_text!r},并非一个大于1的正整数'

    collected_values = []
    for value_item in get_all_numbers(answer_text):
        if value_item <= value - 1000:
            collected_values.append(value_item)

    collected_values = sorted(set(collected_values))
    if len(collected_values) >= 10:
        return True, f'检测到{len(collected_values)}个不大于{value - 1000}的数字:{collected_values!r}'
    else:
        return False, f'检测到{len(collected_values)}个不大于{value - 1000}的数字,未达到10个:{collected_values!r}'


def _en_checker_3(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
    try:
        value = int(user_text.strip())
        if value <= 1:
            raise ValueError
    except (TypeError, ValueError):
        return False, f'You entered {user_text!r}, which is not a positive integer greater than 1'

    collected_values = []
    for value_item in get_all_numbers(answer_text):
        if value_item <= value - 1000:
            collected_values.append(value_item)

    collected_values = sorted(set(collected_values))
    if len(collected_values) >= 10:
        return True, f'Detected {len(collected_values)} numbers not greater than {value - 1000}: {collected_values!r}'
    else:
        return False, f'Detected {len(collected_values)} numbers not greater than {value - 1000}, ' \
                      f'but it doesn\'t reach 10: {collected_values!r}'


register_question(
    {
        'cn': CN_TEXT_3,
        'en': EN_TEXT_3,
    },
    checkers={
        'cn': _cn_checker_3,
        'en': _en_checker_3,
    },
    name={'cn': '2-3 越说越小', 'en': '2-3'},
    level=2,
)

CN_TEXT_4 = """
第二章第四题(警世名言),请在不提及1,4,5这三个字符的情况下让模型回答114514,不要有多余的字符。
"""
EN_TEXT_4 = """
For the fourth question in chapter 2, Please make the model answer "114514" without mentioning the characters 1, 4, and 5, and without any extra characters.
"""


def _cn_checker_4(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
    if "1" in user_text or "4" in user_text or "5" in user_text:
        return False, '请不要在提问中出现1、4、5三个数字'

    return answer_text.strip() == '114514', None


def _en_checker_4(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
    if "1" in user_text or "4" in user_text or "5" in user_text:
        return False, 'Please don\'t include the numbers 1, 4, and 5 in the question'

    return answer_text.strip() == '114514', None


register_question(
    {
        'cn': CN_TEXT_4,
        'en': EN_TEXT_4,
    },
    checkers={
        'cn': _cn_checker_4,
        'en': _en_checker_4,
    },
    name={'cn': '2-4 警世名言', 'en': '2-4'},
    level=2,
)

CN_TEXT_5 = """
第二章第五题(开平方数),请输入一个大于一的平方数作为问题,使回答里包含它的平方根对应的数。
"""
EN_TEXT_5 = """
For the fifth question in chapter 2, Please provide a square number greater than one as the question, and the answer should include the number corresponding to its square root.
"""


def _cn_checker_5(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
    try:
        value = int(user_text.strip())
        if value <= 1:
            raise ValueError
        if int(value ** 0.5) ** 2 != value:
            raise ValueError
    except (TypeError, ValueError):
        return False, f'输入内容{user_text!r},并非一个大于1的平方数'

    sq = int(value ** 0.5)
    for value_item in get_all_numbers(answer_text):
        if value_item == sq:
            return True, f'检测到平方根数{sq}'
    else:
        return False, f'未检测到平方根数{sq}'


def _en_checker_5(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
    try:
        value = int(user_text.strip())
        if value <= 1:
            raise ValueError
        if int(value ** 0.5) ** 2 != value:
            raise ValueError
    except (TypeError, ValueError):
        return False, f'The input, {user_text!r}, is not a square number greater than 1'

    sq = int(value ** 0.5)
    for value_item in get_all_numbers(answer_text):
        if value_item == sq:
            return True, f'Detected square root: {sq}'
    else:
        return False, f'Square root {sq} not detected'


register_question(
    {
        'cn': CN_TEXT_5,
        'en': EN_TEXT_5,
    },
    checkers={
        'cn': _cn_checker_5,
        'en': _en_checker_5,
    },
    name={'cn': '2-5 开平方数', 'en': '2-5'},
    level=2,
)

CN_TEXT_6 = """
第二章第六题(得寸进狗),请提一个不包含“狗”这个字的10个字以内的问题,使回答中“狗”这个字出现的次数至少是问题字数的2倍。
"""
EN_TEXT_6 = """
For the sixth question in chapter 2, Please ask a question in under 10 words without the word "dog" and ensure that the word "dog" appears at least twice in the answer for each word in the question.
"""


def _cn_checker_6(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
    if len(user_text) > 10:
        return False, '问题不得超过10个字'
    if '狗' in user_text:
        return False, '问题不得包含“狗”字'

    dog_count = len(re.findall('狗', answer_text))
    if dog_count >= len(user_text) * 2:
        return True, f'“狗”字的出现次数为{dog_count}次'
    else:
        return False, f'“狗”字的出现次数为{dog_count}次,未达到{len(user_text) * 2}次'


def _en_checker_6(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
    q_words = re.findall(r'\w+', user_text.lower())
    if len(q_words) > 10:
        return False, 'The question must not exceed 10 words'
    if any(word in {'dog', 'dogs'} for word in q_words):
        return False, 'The question must not contain the word "dog" or "dogs"'

    a_words = re.findall(r'\w+', answer_text.lower())
    a_dog_count = sum(1 if word in {'dog', 'dogs'} else 0 for word in a_words)
    if a_dog_count >= len(q_words) * 2:
        return True, f'The word "dog" (or "dogs") appears {a_dog_count} times.'
    else:
        return False, f'The word "dog" (or "dogs") appears {a_dog_count} times, ' \
                      f'which is less than {len(q_words) * 2} times.'


register_question(
    {
        'cn': CN_TEXT_6,
        'en': EN_TEXT_6,
    },
    checkers={
        'cn': _cn_checker_6,
        'en': _en_checker_6,
    },
    name={'cn': '2-6 得寸进狗', 'en': '2-6'},
    level=2
)