"""Accounts on the command line (AV-054 E1) -- for the owner, on the server
(or the Mac with a copy of the database):

    create-owner --email E          the owner account (password asked twice)
    migrate-owner --from OWNER_ID   move every Journey and favourite place of
                                    the single-owner mode to the owner account
    invite --email E                an invitation link (also in the panel)
    reset-link --email E            a password-reset link (also in the panel)
    users                           who has an account

--db PATH chooses the database (default: the server's), --base-url the
address the links point at (default https://app.lentiqa.com).
"""

from __future__ import annotations

import argparse
import getpass
import sqlite3
import sys
from pathlib import Path

from mountain_twin.accounts.store import AccountError, AccountStore, beta_max_users
from mountain_twin.journey.persistence import JourneySqliteDatabase, _transaction

ROOT = Path(__file__).resolve().parents[1]
DEFAULT_DB = ROOT / "data/local/aventurro-journeys.sqlite3"
LOCAL_OWNER = "aventurro-local-user"


def migrate_owner(database: JourneySqliteDatabase, source: str, target: str) -> dict[str, int]:
    """Move the single-owner data to an account: Journeys and favourite
    places (routes, plans, calendar and live tracking hang on the Journey)."""
    connection = database.connect()
    try:
        if (
            connection.execute("SELECT 1 FROM users WHERE user_id = ?", (target,)).fetchone()
            is None
        ):
            raise SystemExit(f"no such account: {target}")
        with _transaction(connection):
            journeys = connection.execute(
                "UPDATE journeys SET owner_id = ? WHERE owner_id = ?", (target, source)
            ).rowcount
            favorites = connection.execute(
                "UPDATE OR IGNORE place_favorites SET owner_id = ? WHERE owner_id = ?",
                (target, source),
            ).rowcount
    finally:
        connection.close()
    return {"journeys": journeys, "favorites": favorites}


def main(argv=None) -> int:
    parser = argparse.ArgumentParser(
        description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
    )
    parser.add_argument("--db", type=Path, default=DEFAULT_DB)
    parser.add_argument("--base-url", default="https://app.lentiqa.com")
    sub = parser.add_subparsers(dest="command", required=True)
    owner = sub.add_parser("create-owner")
    owner.add_argument("--email", required=True)
    owner.add_argument(
        "--password-stdin", action="store_true", help="read the password from stdin (scripts)"
    )
    migrate = sub.add_parser("migrate-owner")
    migrate.add_argument("--from", dest="source", default=LOCAL_OWNER)
    migrate.add_argument("--to", dest="target", help="account id (default: the owner account)")
    for name in ("invite", "reset-link"):
        sub.add_parser(name).add_argument("--email", required=True)
    sub.add_parser("users")
    args = parser.parse_args(argv)
    database = JourneySqliteDatabase(args.db)
    store = AccountStore(database)
    try:
        if args.command == "create-owner":
            if args.password_stdin:
                password = sys.stdin.readline().rstrip("\n")
            else:
                password = getpass.getpass("Hasło: ")
                if password != getpass.getpass("Powtórz hasło: "):
                    raise SystemExit("Hasła się różnią.")
            user = store.create_user(args.email, password, "OWNER")
            store.record_consent(user.user_id)
            print(f"Konto właściciela: {user.user_id} ({user.email})")
        elif args.command == "migrate-owner":
            target = args.target or next(
                (u.user_id for u in store.users() if u.role == "OWNER"), None
            )
            if target is None:
                raise SystemExit("Najpierw create-owner.")
            print(migrate_owner(database, args.source, target))
        elif args.command in ("invite", "reset-link"):
            owner_id = next((u.user_id for u in store.users() if u.role == "OWNER"), None)
            if owner_id is None:
                raise SystemExit("Najpierw create-owner.")
            if args.command == "invite":
                token, expires_at = store.invite(owner_id, args.email, max_users=beta_max_users())
                print(f"{args.base_url}/aventurro/auth.html?invitation={token}")
                print(f"ważne do {expires_at}, jednorazowe")
            else:
                token = store.reset_link_token(args.email)
                print(f"{args.base_url}/aventurro/auth.html?reset={token}")
        elif args.command == "users":
            for user in store.users():
                print(f"{user.role:5} {user.email} {user.user_id} {user.created_at}")
    except AccountError as error:
        raise SystemExit(str(error)) from error
    except sqlite3.Error as error:
        raise SystemExit(f"database: {error}") from error
    finally:
        store.close()
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
