from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.database import get_db
from app.core.security import require_authenticated, require_platform_admin
from app.schemas.auth import (
    AuthConfigResponse,
    AuthSessionResponse,
    HandoffRedeemRequest,
    LoginUrlResponse,
    MeResponse,
    MobileAuthStartResponse,
    MobileOtpRequest,
    MobileOtpVerify,
    MobileRegisterVerify,
    OtpRequestResponse,
    PasswordChangeRequest,
    PasswordChangeResponse,
    ProfileUpdateRequest,
    RefreshTokenRequest,
    RegisterCompleteResponse,
    RegisterRequest,
    TokenExchangeRequest,
    TokenResponse,
    VerifyMobileResponse,
)
from app.services.auth_service import AuthService
from app.services.handoff_store import handoff_store
from app.services.mobile_auth_service import MobileAuthService
from app.services.registration_service import RegistrationService
from shared.exceptions import NotFoundError, UnauthorizedError
from shared.security import CurrentUser

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


@router.get("/config", response_model=AuthConfigResponse)
async def auth_config(db: AsyncSession = Depends(get_db)) -> AuthConfigResponse:
    """پیکربندی OIDC برای frontend — endpoint عمومی."""
    return AuthService(db).get_oidc_config()


@router.get("/login-url", response_model=LoginUrlResponse)
async def login_url(db: AsyncSession = Depends(get_db)) -> LoginUrlResponse:
    """آدرس ورود Keycloak با state و PKCE سمت سرور — endpoint عمومی."""
    return AuthService(db).build_login_url()


@router.post("/token", response_model=TokenResponse)
async def exchange_token(
    payload: TokenExchangeRequest, db: AsyncSession = Depends(get_db)
) -> TokenResponse:
    """تبدیل authorization code به access token (BFF)."""
    return await AuthService(db).exchange_token(payload)


@router.post("/refresh", response_model=TokenResponse)
async def refresh_token(
    payload: RefreshTokenRequest, db: AsyncSession = Depends(get_db)
) -> TokenResponse:
    """تمدید access token با refresh_token تا نشست کاربر قطع نشود."""
    return await AuthService(db).refresh_token(payload.refresh_token)


@router.get("/me", response_model=MeResponse)
async def get_me(
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(require_authenticated),
) -> MeResponse:
    return await AuthService(db).get_me(user)


@router.patch("/me", response_model=MeResponse)
async def update_me(
    payload: ProfileUpdateRequest,
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(require_authenticated),
) -> MeResponse:
    """به‌روزرسانی پروفایل کاربر جاری (نام نمایشی و ایمیل)."""
    return await AuthService(db).update_profile(user, payload)


@router.post("/password", response_model=PasswordChangeResponse)
async def change_password(
    payload: PasswordChangeRequest,
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(require_authenticated),
) -> PasswordChangeResponse:
    """تغییر یا تنظیم رمز عبور کاربر جاری."""
    return await AuthService(db).change_password(user, payload)


@router.post("/register", response_model=OtpRequestResponse, status_code=201)
async def register_user(
    payload: RegisterRequest,
    db: AsyncSession = Depends(get_db),
) -> OtpRequestResponse:
    """ثبت‌نام با ایمیل/نام کاربری/رمز + ارسال OTP موبایل."""
    return await RegistrationService(db).register_with_credentials(payload)


@router.post("/register/verify-mobile", response_model=AuthSessionResponse)
async def verify_registration_mobile(
    payload: MobileOtpVerify,
    db: AsyncSession = Depends(get_db),
) -> AuthSessionResponse:
    """تکمیل ثبت‌نام پس از تأیید OTP (پس از register)."""
    return await RegistrationService(db).complete_registration_verify(payload)


@router.post("/session/redeem", response_model=TokenResponse)
async def redeem_session_handoff(payload: HandoffRedeemRequest) -> TokenResponse:
    """تبدیل کد handoff (از Keycloak theme) به توکن SSO — یکبارمصرف."""
    raw = handoff_store.pop(payload.handoff_code)
    if raw is None:
        raise UnauthorizedError("کد ورود منقضی یا نامعتبر است")
    return TokenResponse(
        access_token=raw["access_token"],
        refresh_token=raw.get("refresh_token"),
        expires_in=raw.get("expires_in", 3600),
        token_type=raw.get("token_type", "Bearer"),
    )


@router.post("/mobile/start", response_model=MobileAuthStartResponse)
async def mobile_auth_start(
    payload: MobileOtpRequest,
    db: AsyncSession = Depends(get_db),
) -> MobileAuthStartResponse:
    """ورود/ثبت‌نام یکپارچه — بک‌اند تشخیص می‌دهد کاربر عضو است یا نه."""
    return await MobileAuthService(db).start(payload)


@router.post("/mobile/complete", response_model=AuthSessionResponse)
async def mobile_auth_complete(
    payload: MobileRegisterVerify,
    db: AsyncSession = Depends(get_db),
) -> AuthSessionResponse:
    """تأیید OTP و ورود یا ثبت‌نام + صدور توکن SSO."""
    return await MobileAuthService(db).complete(payload)


@router.post("/login/mobile", response_model=OtpRequestResponse)
async def login_mobile_request_otp(
    payload: MobileOtpRequest,
    db: AsyncSession = Depends(get_db),
) -> OtpRequestResponse:
    """درخواست OTP برای ورود کاربر موجود."""
    start = await MobileAuthService(db).start(payload)
    if start.intent != "login":
        raise NotFoundError("حسابی با این شماره یافت نشد. ابتدا ثبت‌نام کنید")
    return OtpRequestResponse(
        message=start.message,
        expires_in=start.expires_in,
        skipped=start.skipped,
    )


@router.post("/login/mobile/verify", response_model=AuthSessionResponse)
async def login_mobile_verify(
    payload: MobileOtpVerify,
    db: AsyncSession = Depends(get_db),
) -> AuthSessionResponse:
    """ورود با OTP برای کاربر موجود."""
    return await MobileAuthService(db).complete_login(payload)


@router.post("/register/mobile", response_model=OtpRequestResponse)
async def register_mobile_request_otp(
    payload: MobileOtpRequest,
    db: AsyncSession = Depends(get_db),
) -> OtpRequestResponse:
    """ثبت‌نام فقط با موبایل — مرحله ارسال OTP."""
    return await RegistrationService(db).request_mobile_register_otp(payload)


@router.post("/register/mobile/verify", response_model=AuthSessionResponse, status_code=201)
async def register_mobile_verify(
    payload: MobileRegisterVerify,
    db: AsyncSession = Depends(get_db),
) -> AuthSessionResponse:
    """ثبت‌نام فقط با موبایل — تأیید OTP و ساخت حساب."""
    return await RegistrationService(db).complete_mobile_register(payload)


@router.post("/mobile/request", response_model=OtpRequestResponse)
async def request_mobile_verification(
    payload: MobileOtpRequest,
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(require_authenticated),
) -> OtpRequestResponse:
    """ارسال OTP برای تأیید موبایل کاربر SSO (پس از لاگین)."""
    return await RegistrationService(db).request_verify_mobile(user, payload.mobile)


@router.post("/mobile/verify", response_model=VerifyMobileResponse)
async def verify_mobile(
    payload: MobileOtpVerify,
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(require_authenticated),
) -> VerifyMobileResponse:
    """تأیید موبایل کاربر SSO."""
    return await RegistrationService(db).verify_mobile_for_user(user, payload)
