"""
routers/auth_router.py
------------------------
Registration, login, email verification, and profile management.

Security notes:
  * Passwords are never stored or logged in plaintext — only bcrypt hashes.
  * All inputs are validated by Pydantic schemas before touching the DB.
  * All DB queries use the SQLAlchemy ORM (parameterized under the hood),
    so there is no raw string-interpolated SQL anywhere in this file —
    this is the primary SQL-injection defense.
  * Age eligibility (18-30) is enforced server-side, not just in the UI.
"""

from datetime import date, datetime, timezone

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session

from .. import db_models, schemas
from ..auth import hash_password, verify_password, create_access_token, get_current_user
from ..config import settings
from ..database import get_db
from ..services.email_service import generate_verification_token, send_verification_email

router = APIRouter(prefix="/auth", tags=["auth"])


def _calculate_age(dob: date) -> int:
    today = date.today()
    return today.year - dob.year - ((today.month, today.day) < (dob.month, dob.day))


@router.post("/register", response_model=schemas.UserProfile, status_code=status.HTTP_201_CREATED)
def register(payload: schemas.UserRegister, db: Session = Depends(get_db)):
    age = _calculate_age(payload.date_of_birth)
    if not (settings.MIN_AGE <= age <= settings.MAX_AGE):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"This study is for participants aged {settings.MIN_AGE}-{settings.MAX_AGE}.",
        )

    existing = db.query(db_models.User).filter(db_models.User.email == payload.email).first()
    if existing:
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Email already registered.")

    verify_token = generate_verification_token()
    user = db_models.User(
        email=payload.email,
        password_hash=hash_password(payload.password),
        display_name=payload.display_name,
        date_of_birth=payload.date_of_birth,
        email_verify_token=verify_token,
        email_verify_sent_at=datetime.now(timezone.utc),
    )
    db.add(user)
    db.commit()
    db.refresh(user)

    send_verification_email(user.email, verify_token)
    return user


@router.post("/login", response_model=schemas.Token)
def login(payload: schemas.UserLogin, db: Session = Depends(get_db)):
    user = db.query(db_models.User).filter(db_models.User.email == payload.email).first()
    if not user or not verify_password(payload.password, user.password_hash):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect email or password."
        )
    if not user.is_active:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Account is disabled.")

    token = create_access_token(subject=user.email)
    return schemas.Token(access_token=token)


@router.post("/verify-email")
def verify_email(payload: schemas.EmailVerifyRequest, db: Session = Depends(get_db)):
    user = db.query(db_models.User).filter(db_models.User.email_verify_token == payload.token).first()
    if not user:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid or expired token.")
    user.is_email_verified = True
    user.email_verify_token = None
    db.commit()
    return {"detail": "Email verified successfully."}


@router.get("/me", response_model=schemas.UserProfile)
def get_profile(current_user: db_models.User = Depends(get_current_user)):
    return current_user


@router.put("/me", response_model=schemas.UserProfile)
def update_profile(
    payload: schemas.UserProfileUpdate,
    db: Session = Depends(get_db),
    current_user: db_models.User = Depends(get_current_user),
):
    if payload.display_name is not None:
        current_user.display_name = payload.display_name
    db.commit()
    db.refresh(current_user)
    return current_user


@router.post("/consent")
def record_consent(
    db: Session = Depends(get_db), current_user: db_models.User = Depends(get_current_user)
):
    current_user.consent_given_at = datetime.now(timezone.utc)
    db.commit()
    return {"detail": "Consent recorded.", "consent_given_at": current_user.consent_given_at}
