import argparse
from . import classes as j
import getpass
import colorama


my_parser = argparse.ArgumentParser(
    description='A CLI email client.', prog='CLImail')
# Add the arguments
# my_parser.add_argument('-email',
#                        metavar='email',
#                        type=str,
#                        help='The email to sign in as.',
#                        required=True)
# my_parser.add_argument('-password',
#                        metavar='password',
#                        type=str,
#                        help='The password to sign in to the email with.',
#                        required=True)
my_parser.add_argument('-server',
                       metavar='server',
                       type=str,
                       help='The server to sign in with, i.e gmail.com or outlook.com',
                       default='gmail.com',
                       required=False)
my_parser.add_argument('-smtp_port',
                       metavar='smtp_port',
                       type=str,
                       help='The port to sign into the SMTP server with, is defaulted to 465',
                       default=465,
                       required=False)
my_parser.add_argument('-imap_port',
                       metavar='imap_port',
                       type=str,
                       help='The port to sign into the IMAP4 server with, is defaulted to 993',
                       default=993,
                       required=False)

# Execute the parse_args() method
args = my_parser.parse_args()
password = getpass.getpass('Password (pasting is not supported): ')
user = input('Email: ')
try:
    U = j.User(password=password, user=user, server=args.server,
               imap_port=args.imap_port, smtp_port=args.smtp_port)  # login
except Exception as e:
    print(e)
    my_parser.exit()
else:
    print('Logged in as', user)
while True:
    try:
        colorama.init(True)
        '''
        BE WARNED: this is very ugly - I probably wrote this code while drunk because I have no clue how I did it.
        (I know i can use click but i don't wanna)
        '''
        parser = argparse.ArgumentParser(
            description='A CLI email client.', prog='CLImail')
        cmd = input('>>>')
        subparsers = parser.add_subparsers()
        help = subparsers.add_parser('help',
                                     help='Shows this message.')
        help.set_defaults(func=lambda: parser.print_help())
        selectmail = subparsers.add_parser('selectmailbox', aliases=['select_mailbox', 'select'],
                                           help='Selects a mailbox. \n NOTE: all mailboxes can be found with the "lmb" command.')
        selectmail.add_argument('-mailbox', required=True,
                                help='The mailbox to select.', nargs='*')
        selectmail.add_argument('-readonly', required=False,
                                help='Readonly mode or not.', type=bool, default=False)
        selectmail.set_defaults(
            func=lambda: U.select_mailbox(" ".join(args.mailbox), args.readonly))
        cancelmailbox = subparsers.add_parser('unselect', aliases=['unselect_mailbox', 'cancel_mailbox'],
                                              help='Unselects the current mailbox.')
        cancelmailbox.set_defaults(func=lambda: U.unselect_mailbox())
        list_mailboxes = subparsers.add_parser('listmailboxes', aliases=['lmb', 'mailboxes'],
                                               help='Lists all of the mail boxes the current user has.')
        list_mailboxes.set_defaults(func=lambda: print(U.list_mailboxes()))
        sendmail = subparsers.add_parser('sendmail', aliases=['send', 'sendmessage'],
                                         help='Sends a message.')
        sendmail.add_argument(
            '-reciever', help='The address to mail.', required=True, type=str)
        sendmail.add_argument(
            '-content', help='Body of the message.', required=False, nargs='*', type=str, default=['None'])
        sendmail.add_argument('-subject', help='The subject',
                              required=False, nargs='*', type=str, default=['None'])
        sendmail.add_argument('-cc', help='Carbon copy - addresses to send the mail to as well, seperated by spaces.',
                              required=False, type=str, default=None, nargs='*')
        sendmail.add_argument(
            '-to_attach', help='List of filenames/fps to attach to the mail, seperated by spaces.', required=False, type=str, nargs="*")
        sendmail.set_defaults(func=lambda: (U.sendmail(args.reciever, " ".join(args.content), " ".join(args.subject), args.cc, args.to_attach),
                                            print('Email sent successfully to', args.reciever+'!')))
        unread = subparsers.add_parser('unread', aliases=['unreads'],
                                       help='Whether or not the current user has unread emails.')
        unread.set_defaults(func=lambda: print(
            f'You {int(not U.is_unread()) * "do not"} currently have unread messages!'))
        check_mail = subparsers.add_parser('checkmail', aliases=['checkmessages', 'check_mail', 'check_messages'],
                                           help='Checks the specified number of messages the user has in the current mailbox.')
        check_mail.add_argument(
            '-size', default=10, help='Number of messages to check', type=int, required=False)
        check_mail.add_argument(
            '-save', type=bool, default=False, required=False)
        check_mail.add_argument('-path', default=r'\tmp',
                                required=False, type=str)
        check_mail.set_defaults(func=lambda:
                                list(map(lambda m: (print(U.mail_from_template(U.mail_from_id(m))), [print(colorama.Fore.GREEN + f'{i.rsplit("/")[-1]} was saved at {i}!') for i in U.save_attachments(U.mail_from_id(m), args.path)] if args.save else None), U.mail_ids_as_str(args.size))))  # don't even ask
        current = subparsers.add_parser('current', aliases=[
                                        'current_mailbox', 'current_mail'], help='The current mailbox selected.')
        current.set_defaults(func=lambda: print(U.current_mailbox))
        close = subparsers.add_parser('close', aliases=['quit', 'cancel'],
                                      help='Logout of SMTP and IMAP4 server, close and overwrite all login data.')
        close.set_defaults(func=lambda: (
            U.close(), parser.exit()))
        search = subparsers.add_parser('search', aliases=[
            'searchmail', 'searchmessages'], help='Takes in a string and criteria, and returns messages that match.')
        search.add_argument('-string', required=False,
                            default=None, type=str, nargs='*')
        search.add_argument('-criteria', required=False,
                            nargs='*', default=['(UNSEEN)'], type=str)
        search.add_argument('-size', required=False, default=10, type=int)
        search.set_defaults(func=lambda: [print(U.mail_from_template(
            U.mail_from_id(i))) for i in U.search(args.string if args.string is None else " ".join(args.string), " ".join(args.criteria), size=args.size)])
        subscribe = subparsers.add_parser(
            'subscribe', help='Subscribes to a mailbox.')
        subscribe.add_argument('-mailbox', required=True, type=str)
        subscribe.set_defaults(func=lambda: U.subscribe(args.mailbox))
        unsubscribe = subparsers.add_parser(
            'unsubscribe', help='Unsubscribes TO a mailbox.')
        unsubscribe.add_argument('-mailbox', required=True, type=str)
        unsubscribe.set_defaults(func=lambda: U.unsubscribe(args.mailbox))
        rename = subparsers.add_parser(
            'rename', aliases=['renamemailbox', 'renamebox'])
        rename.add_argument('-old_mailbox', required=True, type=str,)
        rename.add_argument('-new_mailbox', required=True, type=str,)
        rename.set_defaults(func=lambda: (U.rename_mailbox(args.old_mailbox, args.new_mailbox), print(
            f'Renamed mailbox {args.old_mailbox} to {args.new_mailbox}.')))
        checksingmail = subparsers.add_parser(
            'mail', aliases=['message'], help='Returns the mail content from ID passed.')
        checksingmail.add_argument('-id', required=True, type=int)
        checksingmail.set_defaults(func=lambda: print(
            U.mail_from_template(U.mail_from_id(args.id))))
        getmail = subparsers.add_parser(
            'getids', aliases=['get_ids', 'get_mail_ids'], help='Gets a specified amount of latest mail ids from the current mailbox.')
        getmail.add_argument('-size', required=False, default=10, type=int)
        getmail.set_defaults(func=lambda: print(
            *U.mail_ids_as_str(args.size)))
        crtmailbox = subparsers.add_parser(
            'new_mailbox', aliases=['newmailbox', 'new_mail_box'])
        crtmailbox.add_argument('-name', required=True, type=str,)
        crtmailbox.set_defaults(func=lambda: U.create_mailbox(args.name))
        delmailbox = subparsers.add_parser('delete_mailbox', aliases=[
            'removemailbox', 'delete_mail_box'])
        delmailbox.add_argument('-name', required=True, type=str,)
        delmailbox.set_defaults(func=lambda: U.delete_mailbox(args.name))
        delete_mail = subparsers.add_parser('delete_mail', aliases=[
            'deletemail', 'del_mail'], help='Moves number of messages specified to trash.')
        delete_mail.add_argument('-size', required=False, type=int, default=10)
        delete_mail.set_defaults(
            func=lambda: U.delete_mail(args.size))
        delete_ids = subparsers.add_parser('delete_mail_ids', aliases=[
            'deletemailids', 'dmi', 'del_mail_ids'], help='Moves mail ID\'s specified to trash.')
        delete_ids.add_argument('-ids', required=True, type=str, nargs='*')
        delete_ids.set_defaults(func=lambda: U.delete_mail_ids(args.ids))
        clear = subparsers.add_parser('clear', aliases=[
            'clear_trash', 'clear_recycling', 'clear_garbage'], help='Permanently deletes all messages in the trash.')
        clear.set_defaults(func=lambda: U.clear() if input(
            'Are you sure you want to delete all messages in the trash? (y/n) ').lower() == 'y' else print('Cancelled.'))
        refresh = subparsers.add_parser('refresh', aliases=[
            'restart', 'reset', 'reload'], help='Refreshes the current mailbox.')

        refresh.set_defaults(func=lambda: U.refresh())
        contacts = subparsers.add_parser(
            'contacts', aliases=['get_contacts', 'fetch_contacts'], help='Returns a tuple of most recent contacts in the current mailbox.')
        contacts.add_argument('-size', required=False, default=10, type=int)
        contacts.set_defaults(func=lambda: print(U.contacts(args.size)))
        recon = subparsers.add_parser(
            'reconnect', help='Reconnects to the SMTP and IMAP4 servers.')
        recon.set_defaults(func=lambda: U.reconnect())
        save = subparsers.add_parser(
            'save', aliases=['save_attachments', 'save_files', 'savefiles', 'sf'], help='Saves all the attachments from an email to directory specified.')
        save.add_argument('-path', type=str, default=r'/tmp', required=False)
        save.add_argument('-id', type=int, required=True)
        save.set_defaults(func=lambda: print(
            *map((lambda x, y='\\': colorama.Fore.GREEN + f'{x.split(y)[-1]} was saved at {x}!'), U.save_attachments(U.mail_from_id(args.id), args.path)), sep='\n'))

        args = parser.parse_args(cmd.split())
        # run the function associated with each command
        args.__dict__['func']()
    except BaseException as e:
        if len(str(e)) < 1 or str(e) == '0':
            if 'y' in input('Do you want to quit? (y/n): ').lower():
                parser.exit()
            else:
                continue
        print('Error: ', e)
