import hashlib
import hmac
from typing import Annotated

from cryptography.fernet import Fernet
from fastapi import Depends, Form
from sqlmodel import Session, select

from rvpc.auth.text_fields import decrypt_content
from rvpc.auth.tokens.user_tokens import AuthentifiedUser
from rvpc.auth.types import (
    DecryptedContent,
    Hashid,
)
from rvpc.auth.utils import require_env
from rvpc.db import SessionDep
from rvpc.models.models import AppUser, CardContent, Video

USERS_KEY = require_env("SECRET_KEY")
EMAIL_KEY = require_env("EMAIL_KEY")


USERS_KEY = USERS_KEY.encode()
EMAIL_KEY = EMAIL_KEY.encode()


def hash_email(email: str) -> Hashid:
    return Hashid(
        hmac.new(USERS_KEY, email.lower().encode(), hashlib.sha256).hexdigest()
    )


def user_key() -> bytes:
    return Fernet.generate_key()


def encrypt_user_key(user_key: bytes) -> bytes:
    f = Fernet(USERS_KEY)
    return f.encrypt(user_key)


def decrypt_user_key(encrypted_user_key: bytes) -> bytes:
    f = Fernet(USERS_KEY)
    return f.decrypt(encrypted_user_key)


def encrypt_email(email: str) -> bytes:
    normalized = email.lower().strip()
    f = Fernet(EMAIL_KEY)
    return f.encrypt(normalized.encode())


def decrypt_email(encrypted_email: bytes) -> str:
    f = Fernet(EMAIL_KEY)
    return f.decrypt(encrypted_email).decode()


def retrieve_or_create_user(email: str, session: Session) -> AppUser:
    hash = hash_email(email)
    user = session.get(AppUser, hash)

    if user is None:
        user = AppUser(
            hashid=hash_email(email),
            encrypted_key=encrypt_user_key(user_key=user_key()),
            encrypted_email=encrypt_email(email=email),
        )
        session.add(user)
        session.commit()
        session.refresh(user)

    return user


def process_sender(
    sender_email: Annotated[str, Form()], session: SessionDep
) -> AppUser:
    return retrieve_or_create_user(sender_email, session)


UserFromMail = Annotated[AppUser, Depends(process_sender)]


def get_user_video(
    user: AuthentifiedUser, id: str, session: SessionDep
) -> Video:
    stmt = select(Video).where(
        Video.user_hashid == user.hashid, Video.id == int(id)
    )
    result = session.exec(stmt).one()

    return result


UserVideo = Annotated[Video, Depends(get_user_video)]


def get_card_content(
    user: AuthentifiedUser, id: str, session: SessionDep
) -> DecryptedContent:
    content_stmt = select(CardContent).where(CardContent.video_id == int(id))
    content = session.exec(content_stmt).one()

    return decrypt_content(
        content=content, user_key=decrypt_user_key(user.encrypted_key)
    )


SelectedCardContent = Annotated[DecryptedContent, Depends(get_card_content)]
