"""MFA domain - data access for TOTP and WebAuthn."""
from __future__ import annotations
from typing import Optional
from uuid import UUID

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from src.domain.auth.mfa_models import UserTotpSecret, WebAuthnCredential


class TotpSecretRepository:
    """TOTP secret CRUD."""

    def __init__(self, db: AsyncSession):
        self._db = db

    async def get_by_user(self, user_id: UUID) -> Optional[UserTotpSecret]:
        result = await self._db.execute(select(UserTotpSecret).where(UserTotpSecret.user_id == user_id))
        return result.scalar_one_or_none()

    async def create(self, user_id: UUID, secret_encrypted: str) -> UserTotpSecret:
        row = UserTotpSecret(user_id=user_id, secret_encrypted=secret_encrypted)
        self._db.add(row)
        await self._db.flush()
        await self._db.refresh(row)
        return row

    async def enable(self, user_id: UUID) -> None:
        from datetime import datetime, timezone

        row = await self.get_by_user(user_id)
        if row:
            row.enabled_at = datetime.now(timezone.utc)
            await self._db.flush()

    async def delete(self, user_id: UUID) -> None:
        result = await self._db.execute(select(UserTotpSecret).where(UserTotpSecret.user_id == user_id))
        row = result.scalar_one_or_none()
        if row:
            await self._db.delete(row)
            await self._db.flush()


class WebAuthnCredentialRepository:
    """WebAuthn credential CRUD."""

    def __init__(self, db: AsyncSession):
        self._db = db

    async def get_by_credential_id(self, credential_id: str) -> Optional[WebAuthnCredential]:
        result = await self._db.execute(
            select(WebAuthnCredential).where(WebAuthnCredential.credential_id == credential_id)
        )
        return result.scalar_one_or_none()

    async def list_for_user(self, user_id: UUID) -> list[WebAuthnCredential]:
        result = await self._db.execute(select(WebAuthnCredential).where(WebAuthnCredential.user_id == user_id))
        return list(result.scalars().all())

    async def create(
        self,
        user_id: UUID,
        credential_id: str,
        public_key: str,
        sign_count: int = 0,
        device_type: Optional[str] = None,
        backed_up: Optional[bool] = None,
        transports: Optional[list[str]] = None,
        name: Optional[str] = None,
    ) -> WebAuthnCredential:
        row = WebAuthnCredential(
            user_id=user_id,
            credential_id=credential_id,
            public_key=public_key,
            sign_count=sign_count,
            device_type=device_type,
            backed_up=backed_up,
            transports=transports,
            name=name,
        )
        self._db.add(row)
        await self._db.flush()
        await self._db.refresh(row)
        return row

    async def update_sign_count(self, credential_id: str, sign_count: int) -> None:
        row = await self.get_by_credential_id(credential_id)
        if row:
            row.sign_count = sign_count
            await self._db.flush()

    async def delete(self, credential_id: str, user_id: UUID) -> bool:
        result = await self._db.execute(
            select(WebAuthnCredential).where(
                WebAuthnCredential.credential_id == credential_id,
                WebAuthnCredential.user_id == user_id,
            )
        )
        row = result.scalar_one_or_none()
        if row:
            await self._db.delete(row)
            await self._db.flush()
            return True
        return False
