from __future__ import annotations

import uuid

from fastapi import HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from aif_platform.server.auth.jwt_tokens import create_access_token
from aif_platform.server.auth.password import hash_password, verify_password
from aif_platform.server.models.persistence import (
    PlatformOrganization,
    PlatformOrgMembership,
    PlatformUser,
)


def _normalize_email(email: str) -> str:
    return email.strip().lower()


async def register_user(
    db: AsyncSession,
    *,
    email: str,
    password: str,
    org_name: str | None = None,
) -> tuple[PlatformUser, str]:
    norm = _normalize_email(email)
    existing = (
        await db.execute(select(PlatformUser).where(PlatformUser.email == norm))
    ).scalar_one_or_none()
    if existing:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="Email already registered.",
        )

    user = PlatformUser(
        email=norm,
        password_hash=hash_password(password),
    )
    db.add(user)
    await db.flush()

    org = PlatformOrganization(
        name=(org_name or "My organization").strip() or "My organization",
    )
    db.add(org)
    await db.flush()

    db.add(
        PlatformOrgMembership(
            user_id=user.id,
            org_id=org.id,
            role="owner",
        )
    )
    await db.commit()
    await db.refresh(user)

    token = create_access_token(user_id=user.id, email=user.email)
    return user, token


async def login_user(db: AsyncSession, *, email: str, password: str) -> tuple[PlatformUser, str]:
    norm = _normalize_email(email)
    user = (
        await db.execute(select(PlatformUser).where(PlatformUser.email == norm))
    ).scalar_one_or_none()
    if not user or not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid email or password.",
        )
    if not verify_password(password, user.password_hash):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid email or password.",
        )
    token = create_access_token(user_id=user.id, email=user.email)
    return user, token


async def get_user_by_id(db: AsyncSession, user_id: uuid.UUID) -> PlatformUser | None:
    return (
        await db.execute(select(PlatformUser).where(PlatformUser.id == user_id))
    ).scalar_one_or_none()


async def change_password(
    db: AsyncSession,
    *,
    user_id: uuid.UUID,
    current_password: str,
    new_password: str,
) -> None:
    user = await get_user_by_id(db, user_id)
    if not user or not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found.",
        )
    if not verify_password(current_password, user.password_hash):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Current password is incorrect.",
        )
    user.password_hash = hash_password(new_password)
    await db.commit()
