import argparse
from datetime import datetime, timedelta, timezone
import json
from time import sleep
from typing import cast, Dict, Optional
from uuid import UUID, uuid4

from sqlalchemy.orm import Session

from . import actions
from .models import PublicJournal, PublicUser
from ..db import SessionLocal
from ..broodusers import bugout_api
from ..utils.settings import INSTALLATION_TOKEN, BOT_INSTALLATION_TOKEN_HEADER


def create_public_journal(args: argparse.Namespace) -> None:
    """
    Create autogenerated public user for public journals access.
    """
    session = SessionLocal()
    try:
        public_journal = PublicJournal(
            journal_id=args.journal,
            user_id=args.user,
        )
        session.add(public_journal)
        session.commit()

        public_journal_json = {
            "journal_id": str(public_journal.journal_id),
            "user_id": str(public_journal.user_id),
            "created_at": str(public_journal.created_at),
            "updated_at": str(public_journal.updated_at),
            "command_to_add_user_to_journal": (
                f"python -m spire.journal.cli holders add -j {str(public_journal.journal_id)}"
                f"-o {str(public_journal.user_id)} -t user -p journals.read journals.entries.read"
            ),
        }
        print(json.dumps(public_journal_json))
    except Exception as e:
        print(str(e))

    finally:
        session.close()


def list_public_journals(args: argparse.Namespace) -> None:
    """
    List all public journals.
    """
    session = SessionLocal()
    try:
        public_journals = session.query(PublicJournal).all()
        public_journals_json = {
            "public_journals": [
                {
                    "journal_id": str(public_journal.journal_id),
                    "user_id": str(public_journal.user_id),
                    "created_at": str(public_journal.created_at),
                    "updated_at": str(public_journal.updated_at),
                }
                for public_journal in public_journals
            ]
        }
        print(json.dumps(public_journals_json))
    except Exception as e:
        print(str(e))

    finally:
        session.close()


def create_public_user(args: argparse.Namespace) -> None:
    """
    Create autogenerated public user for public journals access.
    """
    session = SessionLocal()
    try:
        username = f"public-{args.name}"
        email = f"{username}@bugout.dev"
        generated_password: str = str(uuid4())
        headers = {BOT_INSTALLATION_TOKEN_HEADER: INSTALLATION_TOKEN}

        user = bugout_api.create_user(
            username=username, email=email, password=generated_password, headers=headers
        )
        user_token = bugout_api.create_token(
            username=username, password=generated_password
        )
        user_restricted_token = bugout_api.create_token_restricted(user_token.id)

        public_user = PublicUser(
            user_id=user.id,
            access_token_id=user_token.id,
            restricted_token_id=user_restricted_token.id,
        )
        session.add(public_user)
        session.commit()

        public_user_json = {
            "user_id": str(public_user.user_id),
            "access_token_id": str(public_user.access_token_id),
            "restricted_token_id": str(public_user.restricted_token_id),
            "created_at": str(public_user.created_at),
            "updated_at": str(public_user.updated_at),
        }
        print(json.dumps(public_user_json))
    except Exception as e:
        print(str(e))

    finally:
        session.close()


def list_public_users(args: argparse.Namespace) -> None:
    """
    List all public users.
    """
    session = SessionLocal()
    try:
        public_users = session.query(PublicUser).all()
        public_user_json = {
            "public_users": [
                {
                    "user_id": str(public_user.user_id),
                    "access_token_id": str(public_user.access_token_id),
                    "restricted_token_id": str(public_user.restricted_token_id),
                    "created_at": str(public_user.created_at),
                    "updated_at": str(public_user.updated_at),
                }
                for public_user in public_users
            ]
        }
        print(json.dumps(public_user_json))
    except Exception as e:
        print(str(e))

    finally:
        session.close()


def main() -> None:
    parser = argparse.ArgumentParser(
        description="Administrative actions for Bugout Public access"
    )
    parser.set_defaults(func=lambda _: parser.print_help())
    subcommands = parser.add_subparsers(description="Public commands")

    # Public journal module
    parser_journals = subcommands.add_parser("journals", description="Public journals")
    parser_journals.set_defaults(func=lambda _: parser_journals.print_help())
    subcommands_journals = parser_journals.add_subparsers(
        description="Public journals commands"
    )
    parser_journal_create = subcommands_journals.add_parser(
        "create", description="Create public bugout journal"
    )
    parser_journal_create.add_argument(
        "-j",
        "--journal",
        required=True,
        help="Journal id",
    )
    parser_journal_create.add_argument(
        "-u",
        "--user",
        required=True,
        help="Public user id",
    )
    parser_journal_create.set_defaults(func=create_public_journal)
    parser_journals_list = subcommands_journals.add_parser(
        "list", description="List all public bugout journals"
    )
    parser_journals_list.set_defaults(func=list_public_journals)

    # Public user module
    parser_users = subcommands.add_parser("users", description="Public users")
    parser_users.set_defaults(func=lambda _: parser_users.print_help())
    subcommands_users = parser_users.add_subparsers(
        description="Public user access commands"
    )
    parser_user_create = subcommands_users.add_parser(
        "create", description="Create public bugout user"
    )
    parser_user_create.add_argument(
        "-n",
        "--name",
        required=True,
        help="Name postfix for public bugout user (public-<name>)",
    )
    parser_user_create.set_defaults(func=create_public_user)
    parser_user_list = subcommands_users.add_parser(
        "list", description="List all public bugout users"
    )
    parser_user_list.set_defaults(func=list_public_users)

    args = parser.parse_args()
    args.func(args)


if __name__ == "__main__":
    main()
