"""Main display module"""
import curses
import os

import tudu.cli as cli
import tudu.data_controllers as data
import tudu.exception as exception
import tudu.tui.help as help_ui
import tudu.tui.prompt as prompt
import tudu.tui.task as task
import tudu.tui.ui as ui
import tudu.util as util


def command_mode(screen: ui.Screen, starting_buffer: str = ''):
    """ Handle command mode. Parse user input and display assist mode, help or exceptions if necessary

    :param starting_buffer: Initial input
    """

    db_modified = False
    try:
        user_input = prompt.commandline(screen, startbuf=starting_buffer)
        if not user_input:
            curses.curs_set(False)
            return
        user_input = user_input.strip()
        if user_input.endswith('help') or user_input.endswith('-h'):
            # If user input ends with -h, --help or help get and display help message for
            # appropriate command generated by the argument parser
            command = user_input.split()[0]
            row = 0
            help_msg = help_ui.gen_help(command)
            help_ui.print_help(screen.stdscr, help_msg)
            key = screen.stdscr.getch()
            while key != ord('q'):
                if key == curses.KEY_RESIZE:
                    help_ui.print_help(screen.stdscr, help_msg)
                if key == curses.KEY_UP and row > 0:
                    row -= 1
                    help_ui.print_help(screen.stdscr, help_msg)
                if key == curses.KEY_DOWN and row < screen.h - 3:
                    row += 1
                    help_ui.print_help(screen.stdscr, help_msg)
                key = screen.stdscr.getch()
            return
        elif user_input in ['add', 'rm', 'edit', 'check', 'uncheck', 'sticky']:
            # Assist mode that prompts for possible task attributes, then glue together user_input
            args = cli.get_args(user_input)
            for tag, arg_prompt in args:
                arg_input = prompt.commandline(screen, arg_prompt)
                if arg_input:
                    user_input += f" {tag} {arg_input}"
        try:
            # Try parsing user input, display exceptions in the prompt
            list_name = screen.app.list_name if screen.app.mode != 'main' else None
            cli.tui_controller(user_input, list_name)
            db_modified = True
        except Exception as e:
            prompt.error_prompt(screen, str(e))
        finally:
            return db_modified
    except exception.EscapeKey:
        # ESC has been pressed. Cleanup and exit command mode
        return False


def run_curses(stdscr, mode: str, list_name: str | None):
    """Main loop for main and list modes. Initialize UI and screen objects, then handle user interaction."""
    app = ui.UI(mode, list_name, util.get_username())
    screen = ui.Screen(stdscr, app)

    screen.display_wrapper(app.redraw)
    key = None
    while key != ord('q'):
        key = screen.stdscr.getch()

        if key in [curses.KEY_LEFT, ord('h')]:
            app.go_left()
        elif key in [curses.KEY_DOWN, ord('j')]:
            app.go_down()
        elif key in [curses.KEY_UP, ord('k')]:
            app.go_up()
        elif key in [curses.KEY_RIGHT, ord('l')]:
            app.go_right()
        elif key == curses.KEY_ENTER or key in [10, 13]:
            if app.mode == 'main':
                app.go_right()
            else:
                app.check_task()
        elif key == ord(' '):
            app.check_task()
        elif key == ord(':'):
            # show command prompt and take user input until ESC or ENTER is pressed
            if screen.display_wrapper(command_mode):
                # user entered a valid command, modifying the database
                app.modified = True
        elif key == ord('i'):
            app.toggle_v_mode()
        elif key == ord('a'):
            buf = 'add ' if app.mode == 'main' else 'add . '
            if screen.display_wrapper(command_mode, buf):
                # user entered a valid command, modifying the database
                app.modified = True
        elif key == ord('e'):
            # open command prompt with start of edit command
            buf = f"edit '{app.get_selected()}' " if app.mode == 'main' else f"edit . '{app.get_selected()}' "
            if screen.display_wrapper(command_mode, buf):
                # user entered a valid command, modifying the database
                app.modified = True
        elif key == ord('d'):
            # ask if user wants to delete entry
            buf = f"rm '{app.get_selected()}' " if app.mode == 'main' else f"rm . '{app.get_selected()}' "
            if screen.display_wrapper(command_mode, buf):
                # user entered a valid command, modifying the database
                app.modified = True
        elif key == curses.KEY_RESIZE:
            # handle window resize
            screen.resize()

        screen.display_wrapper(app.redraw)

        if app.list_finished:
            # if the last task on the list has been checked
            # display a congratulations message  and offer to delete the list
            screen.display_wrapper(prompt.regular_prompt,
                                   'Well done! Would you like to delete this list now?  [y/N]', 2)
            key = screen.stdscr.getch()
            if key == ord('y'):
                data.remove_list(app.list_name)
                app.go_left()
                # app.modified != True, because app.go_left called app.get_items
                # and all tasks are done, so welcome message won't change
            screen.clear_prompt()
            screen.display_wrapper(app.redraw)
            app.list_finished = False


def run(mode='main', list_name=None, task_name=None, center=False, color=None):
    """ Running tui in selected mode """
    os.environ.setdefault("ESCDELAY", "25")
    stdscr = curses.initscr()
    if mode == 'task':
        curses.wrapper(task.run_task, task_name, list_name, center, color)
    else:
        curses.wrapper(run_curses, mode, list_name)
