"""
Authentication Schemas
Login, registration, OTP, and token management
"""
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, Field, EmailStr, field_validator
import re

from app.schemas.user import UserResponse


class LoginRequest(BaseModel):
    """Login with email or phone (account must be OTP-verified)."""
    email: Optional[EmailStr] = Field(None, description="Email address")
    phone: Optional[str] = Field(None, description="Phone number with country code")
    fcm_token: Optional[str] = Field(None, description="FCM token for push notifications")
    
    @field_validator("phone", mode="before")
    @classmethod
    def coerce_phone_e164(cls, v):
        if v is None:
            return v
        if isinstance(v, int):
            v = str(v)
        elif isinstance(v, float):
            v = str(int(v))
        digits = "".join(c for c in str(v).strip() if c.isdigit())
        if not digits:
            return str(v).strip()
        return f"+{digits}"
    
    @field_validator("phone")
    @classmethod
    def validate_phone(cls, v):
        if v is not None:
            pattern = r"^\+[1-9]\d{6,14}$"
            if not re.match(pattern, v):
                raise ValueError("Invalid phone number format. Use international format: +1234567890")
        return v
    
    def model_post_init(self, __context):
        if not self.email and not self.phone:
            raise ValueError("Either email or phone is required")


class RegisterRequest(BaseModel):
    """
    Complete signup after OTP verification (Bearer access token from verify-otp required).
    """
    email: Optional[EmailStr] = Field(None, description="Optional email for profile")
    phone: Optional[str] = Field(None, description="Must match verified phone if sent")
    first_name: Optional[str] = Field(None, max_length=100, description="First name")
    last_name: Optional[str] = Field(None, max_length=100, description="Last name")
    role: str = Field(default="passenger", pattern="^(passenger|driver)$", description="User role")
    fcm_token: Optional[str] = Field(None, description="FCM token for push notifications")
    profile_picture_base64: str = Field(
        ...,
        min_length=24,
        description="Profile photo as base64 or data URL (image/jpeg, image/png, image/webp; max 5MB decoded)",
    )
    
    @field_validator("phone")
    @classmethod
    def validate_phone(cls, v):
        if v is not None and str(v).strip():
            pattern = r"^\+[1-9]\d{6,14}$"
            if not re.match(pattern, v):
                raise ValueError("Invalid phone number format")
        return v
    
    def model_post_init(self, __context):
        return


class OTPSendRequest(BaseModel):
    """Send OTP to phone (international format, e.g. +923001234567)."""
    phone: str = Field(..., description="Phone number with country code")
    purpose: str = Field(default="verification", description="OTP purpose")
    
    @field_validator("phone", mode="before")
    @classmethod
    def coerce_phone_e164(cls, v):
        if v is None:
            return v
        if isinstance(v, int):
            v = str(v)
        elif isinstance(v, float):
            v = str(int(v))
        digits = "".join(c for c in str(v).strip() if c.isdigit())
        if not digits:
            return str(v).strip()
        return f"+{digits}"
    
    @field_validator("phone")
    @classmethod
    def validate_phone(cls, v):
        pattern = r"^\+[1-9]\d{6,14}$"
        if not re.match(pattern, v):
            raise ValueError("Invalid phone number format. Use international format: +1234567890")
        return v


class OTPVerifyRequest(BaseModel):
    """Verify OTP for phone."""
    phone: str = Field(..., description="Same phone as send-otp")
    otp: str = Field(..., min_length=4, max_length=10, description="OTP code")
    
    @field_validator("phone", mode="before")
    @classmethod
    def coerce_phone_e164(cls, v):
        if v is None:
            return v
        if isinstance(v, int):
            v = str(v)
        elif isinstance(v, float):
            v = str(int(v))
        digits = "".join(c for c in str(v).strip() if c.isdigit())
        if not digits:
            return str(v).strip()
        return f"+{digits}"
    
    @field_validator("phone")
    @classmethod
    def validate_phone(cls, v):
        pattern = r"^\+[1-9]\d{6,14}$"
        if not re.match(pattern, v):
            raise ValueError("Invalid phone number format")
        return v


class RefreshTokenRequest(BaseModel):
    """Token refresh request"""
    refresh_token: str = Field(..., description="Refresh token")


class TokenResponse(BaseModel):
    """Authentication token response"""
    access_token: str
    refresh_token: str
    expires_in: int = Field(..., description="Access token expiry in seconds")
    user_id: int
    role: str
    
    class Config:
        json_schema_extra = {
            "example": {
                "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
                "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
                "expires_in": 1800,
                "user_id": 1,
                "role": "passenger"
            }
        }


class VerifyOTPResponse(TokenResponse):
    """
    Tokens plus user profile. Flat fields (`email`, `phone`, `first_name`, …) duplicate key parts of
    `user` so clients can read profile without digging into the nested object.
    """
    email: Optional[str] = Field(None, description="Email on file (may be null before register)")
    phone: Optional[str] = Field(None, description="Verified phone (E.164)")
    first_name: Optional[str] = Field(None, description="First name")
    last_name: Optional[str] = Field(None, description="Last name")
    full_name: str = Field("", description="Computed display name")
    profile_picture: Optional[str] = Field(None, description="Profile image URL")
    is_active: bool = Field(True, description="Account active")
    is_verified: bool = Field(False, description="OTP / verification flag")
    is_phone_verified: bool = Field(False, description="Phone verified")
    is_email_verified: bool = Field(False, description="Email verified")
    created_at: Optional[datetime] = Field(None, description="Row created at")
    wallet_balance: Optional[int] = Field(None, description="Wallet balance in cents")
    user: UserResponse = Field(..., description="Full profile (includes driver fields when applicable)")
    
    class Config:
        json_schema_extra = {
            "example": {
                "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
                "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
                "expires_in": 1800,
                "user_id": 1,
                "role": "passenger",
                "email": "me@example.com",
                "phone": "+923001234567",
                "first_name": None,
                "last_name": None,
                "full_name": "User",
                "profile_picture": None,
                "is_active": True,
                "is_verified": True,
                "is_phone_verified": True,
                "is_email_verified": False,
                "created_at": "2026-04-07T12:00:00",
                "wallet_balance": 0,
                "user": {},
            }
        }


class SocialLoginRequest(BaseModel):
    """Social OAuth login request"""
    provider: str = Field(..., pattern="^(google|facebook|apple)$", description="OAuth provider")
    access_token: str = Field(..., description="OAuth access token")
    id_token: Optional[str] = Field(None, description="ID token (for Apple)")
    fcm_token: Optional[str] = Field(None, description="FCM token for push notifications")


class DeleteAccountRequest(BaseModel):
    """Delete account confirmation"""
    confirm_delete: bool = Field(..., description="Must be true to confirm deletion")


class UserProfileUpdate(BaseModel):
    """User profile update request."""
    first_name: Optional[str] = Field(None, min_length=1, max_length=100)
    last_name: Optional[str] = Field(None, max_length=100)
    email: Optional[EmailStr] = Field(None)
    profile_picture_base64: Optional[str] = Field(
        None,
        min_length=24,
        description="Profile photo as base64 or data URL (image/jpeg, image/png, image/webp; max 5MB decoded)",
    )
