import argparse
import hashlib
import os
import secrets

import psycopg
import psycopg.conninfo

POSTGRES_HOST = os.getenv("POSTGRES_HOST")
POSTGRES_PORT = os.getenv("POSTGRES_PORT")
POSTGRES_USER = os.getenv("POSTGRES_USER")
POSTGRES_PASSWORD = os.getenv("POSTGRES_PASSWORD")
POSTGRES_DB = os.getenv("POSTGRES_DB")


def main(stage: str, client_id: str, client_name: str, client_stage: str) -> None:
    key_id = __generate_key_id()

    raw_secret = __generate_raw_secret()

    hashed_secret = __generate_hashed_secret(raw_secret)

    api_key = __generate_api_key(stage, client_name, client_stage, key_id, raw_secret)

    __insert(key_id, client_id, hashed_secret)

    print("Created API Key:", api_key)


def __generate_key_id() -> str:
    return secrets.token_hex(12)


def __generate_raw_secret() -> str:
    return secrets.token_urlsafe(32)


def __generate_hashed_secret(raw_secret: str) -> str:
    return hashlib.sha256(raw_secret.encode()).hexdigest()


def __generate_api_key(stage: str, client_name: str, client_stage: str, key_id: str, raw_secret: str) -> str:
    return f"{stage}.{client_name}.{client_stage}.{key_id}.{raw_secret}"


def __insert(key_id: str, client_id: str, hashed_secret: str) -> None:
    postgres_url = psycopg.conninfo.make_conninfo(
        host=POSTGRES_HOST,
        port=POSTGRES_PORT,
        user=POSTGRES_USER,
        password=POSTGRES_PASSWORD,
        dbname=POSTGRES_DB,
    )
    with psycopg.connect(postgres_url) as conn, conn.cursor() as cur:
        cur.execute(
            """--sql
            INSERT INTO client_api_keys (id, client_id, algorithm, hashed_secret)
            VALUES (%(id)s, %(client_id)s, %(algorithm)s, %(hashed_secret)s)
            """,
            {
                "id": key_id,
                "client_id": client_id,
                "algorithm": "SHA256",
                "hashed_secret": hashed_secret,
            },
        )
        conn.commit()


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Client API Key Creator Script")
    parser.add_argument("--stage", type=str, required=True)
    parser.add_argument(
        "--client-id",
        type=str,
        required=True,
    )
    parser.add_argument(
        "--client-name",
        type=str,
        required=True,
    )
    parser.add_argument("--client-stage", type=str, required=True)

    args = parser.parse_args()
    main(stage=args.stage, client_id=args.client_id, client_name=args.client_name, client_stage=args.client_stage)
