import ipaddress
from datetime import datetime
from typing import Optional, List, Any, Dict, Union

from pydantic import Field, validator

from glQiwiApi.types.base import Base, ExtraBase
from glQiwiApi.types.amount import CurrencyAmount, CurrencyModel
from glQiwiApi.utils.currency_util import Currency


class PassInfo(Base):
    """object: PassInfo"""

    last_pass_change: str = Field(alias="lastPassChange")
    next_pass_change: str = Field(alias="nextPassChange")
    password_used: bool = Field(alias="passwordUsed")


class MobilePinInfo(Base):
    """object: MobilePinInfo"""

    last_mobile_pin_change: Optional[datetime] = Field(alias="lastMobilePinChange")
    mobile_pin_used: bool = Field(alias="mobilePinUsed")
    next_mobile_pin_change: str = Field(alias="nextMobilePinChange")


class PinInfo(Base):
    """object: PinInfo"""

    pin_used: bool = Field(alias="pinUsed")


class AuthInfo(Base):
    """object: AuthInfo"""

    ip: ipaddress.IPv4Address
    bound_email: Optional[str] = Field(None, alias="boundEmail")
    last_login_date: Optional[datetime] = Field(None, alias="lastLoginDate")
    email_settings: Optional[Dict[Any, Any]] = Field(None, alias="emailSettings")
    mobile_pin_info: MobilePinInfo = Field(alias="mobilePinInfo")
    pass_info: PassInfo = Field(alias="passInfo")
    person_id: int = Field(alias="personId")
    pin_info: PinInfo = Field(alias="pinInfo")
    registration_date: datetime = Field(alias="registrationDate")


class SmsNotification(Base):
    """object: SmsNotification"""

    price: CurrencyAmount
    enabled: bool
    active: bool
    end_date: Optional[datetime] = Field(None, alias="endDate")


class IdentificationInfo(Base):
    """object: IdentificationInfo"""

    bank_alias: Optional[str] = Field(None, alias="bankAlias")
    identification_level: Optional[str] = Field(None, alias="identificationLevel")
    passport_expired: Optional[bool] = Field(None, alias="passportExpired")


class NickName(Base):
    """object: NickName"""

    nickname: Optional[str] = None
    can_change: bool = Field(alias="canChange")
    can_use: bool = Field(alias="canUse")
    description: str = ""


class Feature(Base):
    """object: Feature"""

    feature_id: int = Field(alias="featureId")
    feature_value: str = Field(alias="featureValue")
    start_date: str = Field(alias="startDate")
    end_date: str = Field(alias="endDate")


class ContractInfo(Base):
    """object: ContractInfo"""

    blocked: bool = False
    contract_id: int = Field(alias="contractId")
    creation_date: datetime = Field(alias="creationDate")
    identification_info: List[IdentificationInfo] = Field(alias="identificationInfo")
    sms_notification: SmsNotification = Field(alias="smsNotification")
    nickname: NickName
    features: Optional[List[Feature]] = None


class UserInfo(Base):
    """object: UserInfo"""

    default_pay_currency: CurrencyModel = Field(..., alias="defaultPayCurrency")
    default_pay_source: Optional[int] = Field(None, alias="defaultPaySource")
    default_pay_account_alias: Optional[str] = Field(
        None, alias="defaultPayAccountAlias"
    )
    email: Optional[str] = None
    first_transaction_id: Union[str, int, None] = Field(None, alias="firstTxnId")
    language: str
    operator: str
    phone_hash: str = Field(alias="phoneHash")
    promo_enabled: Optional[bool] = Field(None, alias="promoEnabled")

    @validator("default_pay_currency", pre=True)
    def humanize_pay_currency(cls, v):  # type: ignore
        if not isinstance(v, int):
            return v
        return Currency.get(str(v))


class QiwiAccountInfo(ExtraBase):
    auth_info: Optional[AuthInfo] = Field(None, alias="authInfo")
    contract_info: Optional[ContractInfo] = Field(None, alias="contractInfo")
    user_info: Optional[UserInfo] = Field(None, alias="userInfo")


__all__ = ["QiwiAccountInfo"]
