from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel, ConfigDict, Field, field_validator

_ALLOWED_CARD_NETWORKS = {"VISA", "MASTERCARD", "AMEX", "DISCOVER", "JCB", "DINERS"}


# ─── Rate schemas ─────────────────────────────────────────────────────────────

class PricingTemplateRateCreate(BaseModel):
    transaction_type: str
    rate_percentage: Optional[float] = Field(None, ge=0, le=100)
    fixed_fee_cents: int = Field(0, ge=0)
    tier_name: Optional[str] = None
    interchange_basis_points: Optional[int] = None
    markup_basis_points: Optional[int] = None
    card_network: Optional[str] = None

    @field_validator("card_network")
    @classmethod
    def validate_card_network(cls, v: Optional[str]) -> Optional[str]:
        if v is None:
            return None
        upper = v.upper()
        if upper not in _ALLOWED_CARD_NETWORKS:
            raise ValueError(
                f"card_network must be one of {sorted(_ALLOWED_CARD_NETWORKS)} or null"
            )
        return upper


class PricingTemplateRateResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    template_id: int
    transaction_type: str
    rate_percentage: Optional[float]
    fixed_fee_cents: int
    tier_name: Optional[str]
    interchange_basis_points: Optional[int]
    markup_basis_points: Optional[int]
    card_network: Optional[str] = None


# ─── Template schemas ─────────────────────────────────────────────────────────

class PricingTemplateCreate(BaseModel):
    name: str = Field(..., max_length=255)
    description: Optional[str] = None
    pricing_type: str
    billing_cycle: str
    monthly_fee_cents: int = Field(0, ge=0)
    setup_fee_cents: int = Field(0, ge=0)
    rates: List[PricingTemplateRateCreate] = Field(default_factory=list)


class PricingTemplateUpdate(BaseModel):
    name: Optional[str] = Field(None, max_length=255)
    description: Optional[str] = None
    monthly_fee_cents: Optional[int] = Field(None, ge=0)
    setup_fee_cents: Optional[int] = Field(None, ge=0)
    rates: Optional[List[PricingTemplateRateCreate]] = None


class PricingTemplateResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    name: str
    description: Optional[str]
    pricing_type: str
    billing_cycle: str
    monthly_fee_cents: int
    setup_fee_cents: int
    is_active: bool
    parent_template_id: Optional[int]
    created_by_user_id: Optional[int]
    created_at: datetime
    updated_at: Optional[datetime]
    rates: List[PricingTemplateRateResponse] = []


# ─── Assignment schemas ───────────────────────────────────────────────────────

class MerchantPricingAssignRequest(BaseModel):
    template_id: int
    effective_date: datetime
    notes: Optional[str] = None


class BulkAssignRequest(BaseModel):
    merchant_ids: List[int] = Field(..., min_length=1, max_length=500)
    effective_date: datetime
    notes: Optional[str] = None


class MerchantPricingAssignmentResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    merchant_id: int
    template_id: int
    effective_date: datetime
    is_active: bool
    assigned_by_user_id: Optional[int]
    notes: Optional[str]
    created_at: datetime


# ─── Billing record schemas ───────────────────────────────────────────────────

class BillingRecordResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    merchant_id: int
    template_id: Optional[int]
    period_start: datetime
    period_end: datetime
    total_volume_cents: int
    total_platform_fee_cents: int
    monthly_fee_cents: int
    total_due_cents: int
    status: str
    charge_txn_id: Optional[str]
    retry_count: int
    last_error: Optional[str]
    created_at: datetime
    updated_at: Optional[datetime]


# ─── Interchange rate schemas ─────────────────────────────────────────────────

class InterchangeRateCreate(BaseModel):
    card_network: str = Field(..., max_length=50)
    card_type: str = Field(..., max_length=50)
    transaction_type: str = Field(..., max_length=30)
    rate_percentage: float = Field(..., ge=0, le=100)
    fixed_fee_cents: int = Field(0, ge=0)
    description: Optional[str] = None
    effective_from: datetime
    effective_to: Optional[datetime] = None


class InterchangeRateUpdate(BaseModel):
    rate_percentage: Optional[float] = Field(None, ge=0, le=100)
    fixed_fee_cents: Optional[int] = Field(None, ge=0)
    description: Optional[str] = None
    effective_to: Optional[datetime] = None
    is_active: Optional[bool] = None


class InterchangeRateResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    card_network: str
    card_type: str
    transaction_type: str
    rate_percentage: float
    fixed_fee_cents: int
    description: Optional[str]
    effective_from: datetime
    effective_to: Optional[datetime]
    is_active: bool
    created_at: datetime


# ─── Pricing summary schemas ──────────────────────────────────────────────────

class PricingSummaryItem(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    merchant_id: int
    merchant_name: str
    pricing_type: Optional[str]
    total_volume_cents: int
    total_platform_fee_cents: int
    effective_rate: float


class PricingSummaryResponse(BaseModel):
    items: List[PricingSummaryItem]
    total: int
    page: int
    per_page: int


# ─── Billing method schemas ───────────────────────────────────────────────────

class MerchantBillingMethodCreate(BaseModel):
    tsep_token: str
    card_type: Optional[str] = None
    masked_card: Optional[str] = None
    billing_name: Optional[str] = None


class MerchantBillingMethodResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    merchant_id: int
    card_type: Optional[str]
    masked_card: Optional[str]
    billing_name: Optional[str]
    is_active: bool
    created_at: datetime
