from enum import Enum
from fastapi import Query
from pydantic import Field, BaseModel, model_validator, field_validator, ConfigDict
from typing import List, Optional
from pydantic.networks import EmailStr
from datetime import datetime
import re
from src.apps.merchants.utils.functions import check_hostname
from src.apps.base.utils import regexp
from src.apps.base.schemas.common import AddressCreateRequestSchema
from src.apps.merchants.schemas.merchant_payment_history import (
    MerchantPaymentHistorySchema,
)
from .business_profile import (
    BusinessProfileCreateRequestSchema,
    BusinessProfileCreateRequestSchemaV2,
)
from src.apps.merchants.schemas.principals_info import PrincipalInfoCreateRequestSchema
from .business_owner import BusinessOwnerCreateRequestSchema
from .merchant_common import MerchantBase
from src.apps.users.schemas.user_common import UserBase
from src.apps.merchants.schemas.merchant_acceptances import (
    MerchantAcceptancesBase,
    MerchantAcceptancesCreateRequestSchema,
)
# from src.apps.subscriptions.schemas.requests import SubscriptionCreateRequestSchema


class MerchantOwnerCreateRequestSchema(UserBase):
    model_config = ConfigDict(
        from_attributes=True,
        json_schema_extra={
            "example": {
                "email": "johndoe@example.com",
                "password": "StrongPassword@123",
                "confirm_password": "StrongPassword@123",
                "phone": "+9176787678",
                "is_active": True,
                "is_verified": True,
                "identifier": "user12345",
            }
        }
    )
    
    email: Optional[EmailStr] = Field(default=None, description="A valid email address")
    phone: Optional[str] = Field(default=None, description="A valid phone number")
    password: Optional[str] = Field(
        default=None,
        min_length=8,
        max_length=32,
        description="Make sure you choose a strong password.",
    )
    confirm_password: Optional[str] = Field(
        default=None,
        min_length=8, 
        max_length=32, 
        description="Make sure the passwords are same."
    )
    is_active: Optional[bool] = Field(
        default=None,
        description="Activation status of user, false denotes that the user is inactive"
    )
    is_verified: Optional[bool] = Field(
        default=None,
        description="Verification status of user, false denotes that the user is unverified"
    )
    identifier: Optional[str] = Field(default=None, description="")

    @model_validator(mode='before')
    @classmethod
    def validate_passwords(cls, values):
        password: str = values.get("password", "")
        confirm_password: str = values.get("confirm_password", "")

        # Check if passwords match
        if password != confirm_password:
            raise ValueError("Passwords do not match")

        # Password strength checks
        if len(password) < 8 or len(password) > 32:
            raise ValueError("Password length must be between 8 and 32 characters")
        if not re.search(r"[A-Z]", password):
            raise ValueError("Password must contain at least one uppercase letter")
        if not re.search(r"[a-z]", password):
            raise ValueError("Password must contain at least one lowercase letter")
        if not re.search(r"\d", password):
            raise ValueError("Password must contain at least one digit")
        if not re.search(r"[!@#$%^&*(),.?\":{}|<>]", password):
            raise ValueError("Password must contain at least one special character")

        return values


class MerchantCreateRequestSchema(MerchantBase):
    model_config = ConfigDict(
        from_attributes=True,
        json_schema_extra={
            "example": {
                "name": "Grofers",
                "tagline": "We are the best",
                "industry": "Sales",
                "registration_no": "AUI5687",
                "license_no": "87TY5643YU",
                "uin": "87TY5643YU",
                "owner": {
                    "email": "gggrofers@yopmail.com",
                    "password": "weakpassword",
                    "confirm_password": "weakpassword",
                    "phone": "+9199994321056",
                    "first_name": "Garry",
                    "last_name": "Owen",
                },
                "address": {
                    "address_line_1": "16 Haston st",
                    "city": "NY",
                    "state": "San Fransisco",
                    "country": "US",
                    "zipcode": "123456",
                },
            }
        }
    )
    
    owner: MerchantOwnerCreateRequestSchema = Field(
        description="Administrator of this merchant account"
    )
    is_active: Optional[bool] = Field(
        default=None,
        description="Activation status of merchant, false denotes that the merchant is inactive"
    )
    address: Optional[AddressCreateRequestSchema] = Field(
        default=None,
        description="Merchant's residing address"
    )
    verification_code: Optional[int] = Field(
        default=None,
        description="Verification code for sign up"
    )
    tnc_accepted: Optional[bool] = Field(default=None, description="")
    dob: Optional[datetime] = Field(
        default=None,
        description="User date of birth in formate YYYY/MM/DD"
    )


class MerchantUpdateRequestSchema(MerchantBase):
    model_config = ConfigDict(
        from_attributes=True,
        json_schema_extra={
            "example": {
                "name": "Grofers",
                "tagline": "We are the best",
                "industry": "Sales",
                "registration_no": "AUI5687",
                "license_no": "87TY5643YU",
                "uin": "87TY5643YU",
                "is_active": True,
                "is_verified": True,
                "is_onboarded": True,
            }
        }
    )
    
    is_active: Optional[bool] = Field(
        default=None,
        description="Activation status of merchant, false denotes that the merchant is inactive"
    )
    is_verified: Optional[bool] = Field(
        default=None,
        description="Verification status of merchant, false denotes that the merchant is unverified"
    )
    is_onboarded: Optional[bool] = Field(
        default=None,
        description="Onboarding status of merchant, false denotes that the merchant has not completed onboarding"
    )
    address: Optional[AddressCreateRequestSchema] = Field(
        default=None,
        description="A new address for this merchant that needs to be created"
    )
    brand_logo_id: Optional[int] = Field(
        default=None,
        gt=0, 
        description="Uploaded Brand logo ID of merchant"
    )
    first_name: Optional[str] = Field(default=None, description="")
    last_name: Optional[str] = Field(default=None, description="")
    tnc_accepted: Optional[bool] = Field(
        default=None,
        description="Terms & Condition acceptance status of the merchant."
    )
    is_create_account: Optional[bool] = Field(
        default=None,
        description="To create tilled account of the merchant"
    )

    #TODO: Uncomment when SubscriptionCreateRequestSchema is created
    # subscription: Optional[SubscriptionCreateRequestSchema] = Field(
    #     default=None,
    #     description="Subscription info of the merchant"
    # )

    dob: Optional[datetime] = Field(
        default=None,
        description="User date of birth in formate YYYY/MM/DD"
    )
    tilled_customer_id: Optional[str] = Field(default=None, description="Tilled customer id of user")


class HostNameAvailabilityCheckSchema(BaseModel):
    hostname: str = Field(
        description="The hostname that needs to be checked for availability"
    )


class MerchantOnboardRequestSchema(BaseModel):
    model_config = ConfigDict(
        from_attributes=True,
        json_schema_extra={
            "example": {
                "business_profile": {"business_name": ""},
                "business_owners": [{"first_name": "Garry", "last_name": "Owen"}],
                "business_address": {
                    "address_line_1": "16 Haston st",
                    "city": "NY",
                    "state": "San Fransisco",
                    "country": "US",
                    "zipcode": "123456",
                },
            }
        }
    )
    
    business_profile: BusinessProfileCreateRequestSchema = Field(
        description="Business related profile details of merchant"
    )
    business_owners: List[BusinessOwnerCreateRequestSchema] = Field(
        description="Business Owners are people who own the current merchant's business"
    )
    business_address: Optional[AddressCreateRequestSchema] = Field(
        default=None,
        description="Business address of this merchant"
    )
    is_draft: Optional[bool] = Field(
        default=None,
        description="Onboarding form status of merchant, false denotes that the merchant has not submitted the form"
    )
    hostname: Optional[str] = Field(
        default=None,
        description="Preferred subdomain or a custom domaiin for this merchant"
    )

    @field_validator("hostname")
    @classmethod
    def validate_hostname(cls, hostname):
        if hostname is not None:
            allowed = check_hostname(hostname)
            if not allowed:
                raise ValueError(f"{hostname} is not a valid hostname")
        return hostname


class MerchantOnboardRequestSchemaV2(BaseModel):
    model_config = ConfigDict(
        from_attributes=True,
        json_schema_extra={
            "example": {
                "business_profile": {"business_name": ""},
                "business_owners": [{"first_name": "Garry", "last_name": "Owen"}],
                "business_address": {
                    "address_line_1": "16 Haston st",
                    "city": "NY",
                    "state": "San Fransisco",
                    "country": "US",
                    "zipcode": "123456",
                },
                "legal_address": {
                    "address_line_1": "16 Haston st",
                    "city": "NY",
                    "state": "San Fransisco",
                    "country": "US",
                    "zipcode": "123456",
                },
            }
        }
    )
    
    business_profile: Optional[BusinessProfileCreateRequestSchemaV2] = Field(
        default=None,
        description="Business related profile details of merchant"
    )
    business_owners: Optional[List[PrincipalInfoCreateRequestSchema]] = Field(
        default_factory=list,
        description="Principal are people who own the current merchant's business"
    )
    legal_address: Optional[AddressCreateRequestSchema] = Field(
        default=None,
        description="Legal address of this merchant"
    )
    business_address: Optional[AddressCreateRequestSchema] = Field(
        default=None,
        description="DBA(Doing Business as) address of this merchant"
    )
    merchant_acceptance: Optional[MerchantAcceptancesCreateRequestSchema] = Field(
        default=None,
        description="Policy and agreeement Acceptance of merchant"
    )
    is_draft: Optional[bool] = Field(
        default=None,
        description="Onboarding form status of merchant, false denotes that the merchant has not submitted the form"
    )
    hostname: Optional[str] = Field(
        default=None,
        description="Preferred subdomain or a custom domaiin for this merchant"
    )
    payments: Optional[List[MerchantPaymentHistorySchema]] = Field(
        default=None,
        description="payments history for this merchant"
    )

    @field_validator("hostname")
    @classmethod
    def validate_hostname(cls, hostname):
        if hostname is not None:
            allowed = check_hostname(hostname)
            if not allowed:
                raise ValueError(f"{hostname} is not a valid hostname")
        return hostname


class MerchantListFilterSchema(BaseModel):
    search: Optional[str] = Query(
        default=None, description="Search by name, email, phone, city, state, zip etc"
    )
    is_active: Optional[int] = Query(default=0, description="Active status of merchant")
    is_verified: Optional[int] = Query(
        default=0, description="Verified status of merchant"
    )
    is_onboarded: Optional[int] = Query(
        default=0, description="Onboarded status of merchant"
    )
    is_pending: Optional[int] = Query(
        default=0, description="Active status of merchant"
    )
    is_close: Optional[int] = Query(default=0, description="Active status of merchant")
    is_inactive: Optional[int] = Query(
        default=0, description="Active status of merchant"
    )


class MerchantSignerListFilterSchema(BaseModel):
    search: Optional[str] = Query(
        default=None, description="Search by user's name, email, phone, etc"
    )
    name: Optional[str] = Query(default=None, description="Search by user's name")
    email: Optional[str] = Query(default=None, description="Search by user's email")
    phone: Optional[str] = Query(default=None, description="Search by user's phone")
    is_active: Optional[int] = Query(default=0, description="Active status of user")
    is_verified: Optional[int] = Query(
        default=0, description="Verified status of customer"
    )


class AdminMerchantBulkActions(str, Enum):
    cancel_subscription = "cancel_subscription"
    activate_subscription = "activate_subscription"


class AdminMerchantActionSchema(BaseModel):
    action: AdminMerchantBulkActions = Field(
        description="Type of action which needs to be performed."
    )
    ids: List[str] = Field(
        description="An array of merchant_id of the items that you want to perform actions for"
    )

    @field_validator("ids")
    @classmethod
    def validate_ids(cls, v):
        max_limit = 10
        if v is None or len(v) == 0:
            raise ValueError(f"Please provide atleast one plan id")
        if len(v) > max_limit:
            raise ValueError(f"You can provide atmost of {max_limit} plan ids at once")
        for item in v:
            if not regexp.test(item, regexp.MERCHANT_UNIQUE_ID):
                raise ValueError(f"'{item}' is not a valid plan_id")
        return v
