"""
Auth routes — HTTP endpoints for Phase 1.3.1 (signup, me, logout).

This module is the HTTP layer ONLY. Business logic lives in app/services/auth_service.py.
Custom service exceptions are translated to HTTP status codes here.
"""
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer

from app.core.security import CurrentUser, get_current_user
from app.schemas.auth import (
    ChangePasswordRequest,
    ChangePasswordResponse,
    ConfirmRequest,
    ConfirmResponse,
    ForgotPasswordRequest,
    ForgotPasswordResponse,
    GoogleSignInRequest,
    GoogleSignInResponse,
    LoginRequest,
    LoginResponse,
    MeResponse,
    RefreshRequest,
    RefreshResponse,
    ResendConfirmationRequest,
    ResendConfirmationResponse,
    ResetPasswordRequest,
    ResetPasswordResponse,
    SignupRequest,
    SignupResponse,
)
from app.services import auth_service

router = APIRouter(prefix="/auth", tags=["auth"])

# Used by logout to extract raw JWT without re-verifying (Supabase verifies on sign_out)
_bearer_scheme = HTTPBearer(auto_error=True)


# ----------------------------------------------------------------------------
# POST /auth/signup
# ----------------------------------------------------------------------------

@router.post(
    "/signup",
    response_model=SignupResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Classic email/password signup",
    description="Creates a user in auth.users + a row in public.profiles. "
                "Supabase sends a confirmation email automatically. "
                "No JWT is issued at this stage (user must confirm email then login).",
)
def signup(payload: SignupRequest) -> SignupResponse:
    try:
        result = auth_service.signup(
            email=payload.email,
            password=payload.password,
            firstname=payload.firstname,
            lastname=payload.lastname,
            phone=payload.phone,
            profession=payload.profession,
            city=payload.city,
        )
    except auth_service.EmailAlreadyExists:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="Email already registered",
        )
    except auth_service.SupabaseAuthError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Signup failed: {e}",
        )

    return SignupResponse(
        user_id=result.user_id,
        email=result.email,
        email_sent=result.email_sent,
    )


# ----------------------------------------------------------------------------
# GET /auth/me
# ----------------------------------------------------------------------------

@router.get(
    "/me",
    response_model=MeResponse,
    summary="Current authenticated user info",
    description="Returns the current user identity (from JWT) combined with their profile data. "
                "Requires a valid Bearer JWT in the Authorization header.",
)
def me(user: CurrentUser = Depends(get_current_user)) -> MeResponse:
    try:
        result = auth_service.get_me(user.user_id)
    except auth_service.ProfileNotFound:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Profile not found (data inconsistency)",
        )
    except auth_service.SupabaseAuthError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to fetch user info: {e}",
        )

    return MeResponse(
        user_id=result.user_id,
        email=result.email,
        role=result.role,
        firstname=result.firstname,
        lastname=result.lastname,
        phone=result.phone,
        profession=result.profession,
        city=result.city,
    )


# ----------------------------------------------------------------------------
# POST /auth/logout
# ----------------------------------------------------------------------------

@router.post(
    "/logout",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Revoke the current session refresh_token",
    description="Calls Supabase sign_out which revokes the refresh_token. "
                "The access JWT itself remains valid until natural expiration (JWT limitation).",
)
def logout(
    credentials: HTTPAuthorizationCredentials = Depends(_bearer_scheme),
) -> None:
    try:
        auth_service.logout(credentials.credentials)
    except auth_service.SupabaseAuthError as e:
        # Logout failures are usually best-effort; return 500 only on truly unexpected errors.
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Logout failed: {e}",
        )


# ----------------------------------------------------------------------------
# POST /auth/login
# ----------------------------------------------------------------------------

@router.post(
    "/login",
    response_model=LoginResponse,
    summary="Login with email/password",
    description="Authenticates user credentials. Returns tokens + user data in a single payload. "
                "Requires email_confirmed_at IS NOT NULL on the user (blocks unconfirmed signups).",
)
def login(payload: LoginRequest) -> LoginResponse:
    try:
        result = auth_service.login(
            email=payload.email,
            password=payload.password,
        )
    except auth_service.EmailNotConfirmed:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail={"detail": "Email not confirmed", "code": "EMAIL_NOT_CONFIRMED"},
        )
    except auth_service.InvalidCredentials:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid credentials",
        )
    except auth_service.ProfileNotFound:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Profile not found (data inconsistency)",
        )
    except auth_service.SupabaseAuthError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Login failed: {e}",
        )

    return LoginResponse(
        access_token=result.access_token,
        refresh_token=result.refresh_token,
        expires_in=result.expires_in,
        token_type=result.token_type,
        user=MeResponse(
            user_id=result.user.user_id,
            email=result.user.email,
            role=result.user.role,
            firstname=result.user.firstname,
            lastname=result.user.lastname,
            phone=result.user.phone,
            profession=result.user.profession,
            city=result.user.city,
        ),
    )


# ----------------------------------------------------------------------------
# POST /auth/refresh
# ----------------------------------------------------------------------------

@router.post(
    "/refresh",
    response_model=RefreshResponse,
    summary="Refresh access token using a refresh token",
    description="Exchanges a valid refreshToken for a new pair of tokens. "
                "Supabase rotates the refreshToken: the old one is invalidated after this call.",
)
def refresh(payload: RefreshRequest) -> RefreshResponse:
    try:
        result = auth_service.refresh(refresh_token=payload.refresh_token)
    except auth_service.InvalidRefreshToken:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid or expired refresh token",
        )
    except auth_service.SupabaseAuthError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Refresh failed: {e}",
        )

    return RefreshResponse(
        access_token=result.access_token,
        refresh_token=result.refresh_token,
        expires_in=result.expires_in,
        token_type=result.token_type,
    )


# ----------------------------------------------------------------------------
# POST /auth/confirm
# ----------------------------------------------------------------------------

@router.post(
    "/confirm",
    response_model=ConfirmResponse,
    summary="Verify email confirmation token_hash and auto-login",
    description="Called by the mobile app after extracting token_hash from the email deep link "
                "(talk2cv://confirm?token_hash=XXX&type=signup). On success, marks email as confirmed "
                "in Supabase and returns tokens + user data (auto-login, no need to re-type credentials).",
)
def confirm(payload: ConfirmRequest) -> ConfirmResponse:
    try:
        result = auth_service.confirm_signup(
            token_hash=payload.token_hash,
            type=payload.type,
        )
    except auth_service.InvalidConfirmationToken:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid or expired confirmation token",
        )
    except auth_service.ProfileNotFound:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Profile not found (data inconsistency)",
        )
    except auth_service.ConfirmationError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Confirmation failed: {e}",
        )

    return ConfirmResponse(
        access_token=result.access_token,
        refresh_token=result.refresh_token,
        expires_in=result.expires_in,
        token_type=result.token_type,
        user=MeResponse(
            user_id=result.user.user_id,
            email=result.user.email,
            role=result.user.role,
            firstname=result.user.firstname,
            lastname=result.user.lastname,
            phone=result.user.phone,
            profession=result.user.profession,
            city=result.user.city,
        ),
    )


# ----------------------------------------------------------------------------
# POST /auth/resend-confirmation
# ----------------------------------------------------------------------------

@router.post(
    "/resend-confirmation",
    response_model=ResendConfirmationResponse,
    summary="Re-send confirmation email (anti-enumeration)",
    description="Always returns emailSent=true to prevent email enumeration attacks. "
                "Supabase silently skips invalid cases (non-existent email, already confirmed).",
)
def resend_confirmation(payload: ResendConfirmationRequest) -> ResendConfirmationResponse:
    auth_service.resend_confirmation(email=payload.email)
    return ResendConfirmationResponse(email_sent=True)


# ----------------------------------------------------------------------------
# POST /auth/forgot-password
# ----------------------------------------------------------------------------

@router.post(
    "/forgot-password",
    response_model=ForgotPasswordResponse,
    response_model_exclude_none=True,
    summary="Initiate a password reset flow",
    description="Branches on the user's auth provider: email/password -> sends reset email, "
                "Google OAuth -> returns code=GOOGLE_USER, non-existent email -> silent success "
                "(anti-enumeration). Always returns HTTP 200.",
)
def forgot_password(payload: ForgotPasswordRequest) -> ForgotPasswordResponse:
    result = auth_service.forgot_password(email=payload.email)
    return ForgotPasswordResponse(
        email_sent=result.email_sent,
        code=result.code,
    )


# ----------------------------------------------------------------------------
# POST /auth/reset-password
# ----------------------------------------------------------------------------

@router.post(
    "/reset-password",
    response_model=ResetPasswordResponse,
    summary="Apply a password reset with auto-login",
    description="Called by the mobile app after extracting token_hash from the deep link "
                "(talk2cv://reset-password?token_hash=XXX&type=recovery). Verifies the token, "
                "updates the password, and returns tokens + user data (auto-login).",
)
def reset_password(payload: ResetPasswordRequest) -> ResetPasswordResponse:
    try:
        result = auth_service.reset_password(
            token_hash=payload.token_hash,
            new_password=payload.new_password,
        )
    except auth_service.InvalidResetToken:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid or expired reset token",
        )
    except auth_service.ProfileNotFound:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Profile not found (data inconsistency)",
        )
    except auth_service.ResetPasswordError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Password reset failed: {e}",
        )

    return ResetPasswordResponse(
        access_token=result.access_token,
        refresh_token=result.refresh_token,
        expires_in=result.expires_in,
        token_type=result.token_type,
        user=MeResponse(
            user_id=result.user.user_id,
            email=result.user.email,
            role=result.user.role,
            firstname=result.user.firstname,
            lastname=result.user.lastname,
            phone=result.user.phone,
            profession=result.user.profession,
            city=result.user.city,
        ),
    )


# ----------------------------------------------------------------------------
# PATCH /auth/change-password
# ----------------------------------------------------------------------------

@router.patch(
    "/change-password",
    response_model=ChangePasswordResponse,
    status_code=200,
    summary="Change password for an authenticated user",
    description="Re-verifies the current password via sign_in_with_password, then updates "
                "to the new password using the admin client. Requires a valid Bearer JWT.",
)
def change_password_route(
    payload: ChangePasswordRequest,
    current_user: CurrentUser = Depends(get_current_user),
) -> ChangePasswordResponse:
    try:
        auth_service.change_password(
            user_id=current_user.user_id,
            user_email=current_user.email or "",
            current_password=payload.current_password,
            new_password=payload.new_password,
        )
    except auth_service.InvalidCurrentPassword:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Current password is incorrect",
        )
    except auth_service.SupabaseAuthError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Password change failed: {e}",
        )
    return ChangePasswordResponse(success=True)


# ----------------------------------------------------------------------------
# POST /auth/google
# ----------------------------------------------------------------------------

@router.post(
    "/google",
    response_model=GoogleSignInResponse,
    summary="Sign in (or sign up) via Google OAuth",
    description="Called by the mobile app after obtaining an idToken from the native "
                "Google Sign-In SDK. The backend delegates validation to Supabase and "
                "auto-creates the profile on first sign-in (with firstname/lastname from "
                "Google; phone/profession/city remain NULL until the user completes "
                "CompleteProfileScreen). Returns tokens + user data (auto-login).",
)
def google(payload: GoogleSignInRequest) -> GoogleSignInResponse:
    try:
        result = auth_service.google_signin(id_token=payload.id_token)
    except auth_service.InvalidGoogleToken:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid or expired Google token",
        )
    except auth_service.ProfileNotFound:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Profile not found (data inconsistency)",
        )
    except auth_service.GoogleOAuthError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Google OAuth error: {e}",
        )

    return GoogleSignInResponse(
        access_token=result.access_token,
        refresh_token=result.refresh_token,
        expires_in=result.expires_in,
        token_type=result.token_type,
        user=MeResponse(
            user_id=result.user.user_id,
            email=result.user.email,
            role=result.user.role,
            firstname=result.user.firstname,
            lastname=result.user.lastname,
            phone=result.user.phone,
            profession=result.user.profession,
            city=result.user.city,
        ),
    )
