import argparse
import shlex
import sys

import configargparse

from . import __version__
from .models.action import Action
from .models.display_field_token import DisplayFieldToken
from .models.keybinding import Keybinding
from .models.targets import Target, TypeTarget
from .paths import config_file_locations


def parse_arguments(argv: list[str] | None = None) -> argparse.Namespace:
    parser = configargparse.ArgumentParser(
        description="Insert or copy passwords and usernames from Bitwarden using rofi or rofi-likes.",
        default_config_files=config_file_locations,
    )
    parser.add_argument("--version", action="version", version="rofi-rbw " + __version__)
    parser.add_argument(
        "--action",
        "-a",
        dest="action",
        action="store",
        choices=[action.value for action in Action],
        default=Action.TYPE.value,
        help="What to do with the selected entry",
    )
    parser.add_argument("--target", "-t", dest="targets", action="append", help="Which part of the entry do you want?")
    parser.add_argument(
        "--prompt", "-r", dest="prompt", action="store", default="Choose entry", help="Set rofi-rbw's prompt"
    )
    parser.add_argument(
        "--selector-args",
        dest="selector_args",
        action="store",
        default="",
        help="A string of arguments to give to the selector",
    )
    parser.add_argument(
        "--selector",
        dest="selector",
        action="store",
        type=str,
        choices=["rofi", "wofi", "fuzzel", "bemenu"],
        default=None,
        help="Choose the selector frontend",
    )
    parser.add_argument(
        "--clipboarder",
        dest="clipboarder",
        action="store",
        type=str,
        choices=["xsel", "xclip", "wl-copy"],
        default=None,
        help="Choose the application to access the clipboard with",
    )
    parser.add_argument(
        "--typer",
        dest="typer",
        action="store",
        type=str,
        choices=["xdotool", "wtype", "ydotool", "dotool"],
        default=None,
        help="Choose the application to type with",
    )
    parser.add_argument(
        "--clear-after",
        dest="clear",
        action="store",
        type=int,
        default=0,
        help="Limit the duration in seconds passwords stay in your clipboard. When not set or <= 0, passwords stay indefinitely",
    )
    parser.add_argument(
        "--no-help", dest="show_help", action="store_false", help="Don't show a help message about the shortcuts"
    )
    parser.add_argument(
        "--no-folder",
        dest="show_folders",
        action="store_false",
        help=argparse.SUPPRESS,
    )
    parser.set_defaults(show_folders=True)
    parser.add_argument(
        "--display-fields",
        dest="display_fields",
        action="store",
        nargs="+",
        choices=[field.value for field in DisplayFieldToken],
        default=None,
        metavar="DISPLAY_FIELDS",
        help='Ordered list of fields to show in the selection list, given as separate arguments Defaults to "name_with_folder user"',
    )
    parser.add_argument("--no-cache", dest="use_cache", action="store_false", help="Don't save history in cache")
    parser.set_defaults(use_cache=True)
    parser.add_argument(
        "--use-notify-send",
        dest="use_notify_send",
        action="store_true",
        help="Send desktop notification after copying TOTP",
    )
    parser.set_defaults(use_notify_send=False)
    parser.add_argument(
        "--keybindings",
        dest="keybindings",
        action="store",
        type=str,
        default=",".join(
            [
                "Alt+1:type:username:tab:password",
                "Alt+2:type:username",
                "Alt+3:type:password",
                "Alt+4:type:totp",
                "Alt+c:copy:password",
                "Alt+u:copy:username",
                "Alt+t:copy:totp",
                "Alt+m::menu",
                "Alt+s:sync",
            ]
        ),
        help="Define keyboard shortcuts in the format <shortcut>:<action>:<target>, separated with a comma",
    )
    parser.add_argument(
        "--menu-keybindings",
        dest="menu_keybindings",
        action="store",
        type=str,
        default=",".join(["Alt+t:type", "Alt+c:copy"]),
        help="Define the keyboard shortcuts in the target menu in the format <shortcut>:<action> separated with a comma",
    )
    parser.add_argument(
        "--typing-key-delay",
        dest="key_delay",
        action="store",
        type=int,
        default=0,
        help="Set the delay between key presses when typing",
    )
    parser.add_argument(
        "--typing-start-delay",
        dest="start_delay",
        action="store",
        type=int,
        default=0,
        help="Set the typing start delay",
    )
    parser.add_argument(
        "--action-sequence-delay",
        dest="action_sequence_delay",
        action="store",
        type=int,
        default=1000,
        help="Set the delay to wait for a 'delay' step",
    )

    parsed_args = parser.parse_args(argv)

    parsed_args.selector_args = shlex.split(parsed_args.selector_args)

    parsed_args.action = Action(parsed_args.action)

    if parsed_args.targets:
        parsed_args.targets = [Target(target) for target in parsed_args.targets]
    else:
        parsed_args.targets = None

    parsed_args.parsed_keybindings = []
    for keybinding in parsed_args.keybindings.split(","):
        elements = keybinding.split(":")
        parsed_args.parsed_keybindings.append(
            Keybinding(
                elements[0],
                Action(elements[1]) if elements[1] else None,
                [TypeTarget(target_string) for target_string in elements[2:]],
            )
        )

    parsed_args.parsed_menu_keybindings = []
    for keybinding in parsed_args.menu_keybindings.split(","):
        elements = keybinding.split(":")
        parsed_args.parsed_menu_keybindings.append(
            Keybinding(elements[0], Action(elements[1]) if elements[1] else None, None)
        )

    if parsed_args.display_fields is not None:
        display_fields = [DisplayFieldToken(field) for field in parsed_args.display_fields]
    elif not parsed_args.show_folders:
        sys.stderr.write(
            "warning: --no-folder is deprecated and will be removed in a future release. Use --display-fields name_only user instead.\n"
        )
        display_fields = [DisplayFieldToken.NAME_ONLY, DisplayFieldToken.USER]
    else:
        display_fields = [DisplayFieldToken.NAME_WITH_FOLDER, DisplayFieldToken.USER]

    del parsed_args.show_folders
    parsed_args.display_fields = display_fields

    return parsed_args
