import requests
from typing import Union

SERVER = 'http://127.0.0.1:5000/'

INSTRUCTIONS = [
    '---- Instructions ----',
    'This quiz will present a series of multiple choice questions.',
    'You can select your response by entering the index number corresponding with your chosen option(s).',
    'For most questions, you may only select one option.',
    'Some questions allow multiple options to be selected, and will advice you accordingly.',
    'To select multiple options, enter their index number(s) separated by commas.'
]

WELCOME = [
    '---- What *Wanderhome* Playbook Are You? ----',
    '',
    '*Wanderhome* is about going on a journey, and reflecting on how the journey changes us.',
    'The road is full of myriad travellers, each with their rich lives and stories.',
    'This quiz will help you figure out what kinds of stories you will bring to the table.',
    'Will you join me?',
    ''
]

GOODBYE = [
    '---- Thank you for taking the What Wanderhome Playbook Are You? Quiz ----',
    'Programmed and Written by Vivek Santayana',
    'Based on the table-top role-playing game *Wanderhome* by Jay Dragon, published by Possum Creek Games.',
    'Check out Wanderhome at https://possumcreekgames.com/en-gb/pages/wanderhome',
    'I strongly recommend this game: it is amazing!',
    '',
    'Good bye, and may your journeys surprise you!',
    ''
]

def sanitise_text(raw_text:str) -> str:
    format_replacements = {
        '<p>': '',
        '</p>': '\n',
        '<em>': '*',
        '</em>': '*',
        '<strong>': '**',
        '</strong>': '**',
        '&#xe6;': 'æ',
        '&lsquo;': '‘',
        '&rsquo;': '’',
        '&iuml;': 'ï'
    }
    for key, value in format_replacements.items():
        raw_text = raw_text.replace(key, value)
    
    return raw_text

def render(output:list):
    print('\n'.join(['', *output, '']))
    x = input('Press Enter to proceed.')

def render_question(question) -> str:
    print(sanitise_text(raw_text=question['question']))
    print('-- Options --')
    for index, answer in enumerate(question['answers']):
        print(index, sanitise_text(raw_text=answer))
    print('')
    prompt = f'Please select up to {question["select"]} options, separated by commas: ' if question['select'] > 1 else 'Please select an answer: '
    return input(prompt)

def parse_input(raw_answer) -> list:
    try: return list(set(int(answer) for answer in raw_answer.split(',')))
    except: return [ ]

def process_input(answer_input:list, question:dict) -> Union[list, int]: return answer_input[0] if question['select'] == 1 else answer_input

def show_input_error(): input('\n *** Your response was invalid. Please try again *** \n\nPress enter to retry.')

def validate_answer(answers:list, question:dict) -> bool:
    def check_range(answer:int) -> bool: return answer >= 0 and answer < len(question['answers'])
    def check_input_number(answers:list) -> bool: return len(answers) > 0 and len(answers) <= question['select']
    if not check_input_number(answers=answers): return False
    try: return all([check_range(answer=int(answer)) for answer in answers])
    except ValueError: return False

def render_questions() -> dict:
    answers = [ ]
    try:
        questions = requests.get(url=f'{SERVER}/api/questions/').json()
    except Exception as exception:
        print(exception)
        quit()
    for index, question in enumerate(questions):
        answer_valid = False
        while not answer_valid:
            print('')
            print(f'---- Question {index + 1} ----')
            answer = render_question(question)
            answer = parse_input(answer)
            answer_valid = validate_answer(answer, question)
            if not answer_valid: show_input_error()
        answers.append(process_input(answer, question))
    try: return requests.post(url=f'{SERVER}api/submit/',json=answers).json()
    except Exception as exception:
        print(exception)
        quit()

def render_results(results:dict):
    print('\n---- Results ----\n')
    plural = len(results['playbooks']) > 1
    print(f'Your { "results are" if plural else "result is"}:')
    for playbook in results['playbooks']:
        name = list(playbook.keys())[0]
        data = list(playbook.values())[0]
        animals = ''
        for index, animal in enumerate(data['animals']):
            article = 'an' if animal[0] in ['a','e','i', 'o', 'u'] else 'a'
            conjunction = ', or ' if index == len(data['animals']) - 2 else '.' if index == len(data["animals"]) - 1 else ', '
            animals += f'{article} {animal}{conjunction}'
        print(f'\n**The {name[0].upper()}{name[1:]}**\n(pp.{data["pages"]})\n')
        print(sanitise_text(data['flavour']),'\n')
        print(sanitise_text(data['blurb']),'\n')
        print('You are alive. Your care is ',sanitise_text(data['care']),'.\n')
        print('Your animal form is ', animals, '\n')
        print('You can always:')
        for action in data['actions']:
            print('-- ', sanitise_text(action))
        input('\nPress enter to continue.')
    print('\n-- Your score for each playbook: --')
    for playbook, score in results['all_playbooks'].items(): print(f'The {playbook[0].upper()}{playbook[1:]}: {score*"x"} ({round(100*score/results["max_score"])}%)')

def run_quiz():
    render(output=WELCOME)
    render(output=INSTRUCTIONS)
    run = True
    while run:
        render_results(render_questions())
        repeat_prompt_valid = False
        while not repeat_prompt_valid:
            repeat_prompt = input('\nDo you want to do the quiz again? (y) Yes / (n) No: ')
            if repeat_prompt.lower() in ['y', 'n', 'yes', 'no']: repeat_prompt_valid = True
            if not repeat_prompt_valid: show_input_error()
        run = True if repeat_prompt.lower() in ['y', 'yes'] else False
    render(GOODBYE)

"""Running the Quiz"""
if __name__ == '__main__': run_quiz()