"""Loyalty foundation DTOs — Phase 7.0."""
from __future__ import annotations

from datetime import date, datetime
from uuid import UUID

from pydantic import BaseModel, ConfigDict, Field

from app.models.types import (
    CampaignStatus,
    MemberStatus,
    PointAccountStatus,
    ProgramStatus,
    RewardStatus,
    RewardType,
    TierStatus,
)
from app.schemas.common import ORMBase

_FORBID = ConfigDict(extra="forbid")


class LoyaltyProgramCreate(BaseModel):
    model_config = _FORBID

    code: str = Field(max_length=50)
    name: str = Field(max_length=255)
    description: str | None = None
    status: ProgramStatus = ProgramStatus.DRAFT
    points_currency_name: str = Field(default="points", max_length=50)
    currency_code: str = Field(default="IRR", max_length=3)
    is_default: bool = False
    settings: dict | None = None


class LoyaltyProgramUpdate(BaseModel):
    model_config = _FORBID

    name: str | None = Field(default=None, max_length=255)
    description: str | None = None
    status: ProgramStatus | None = None
    points_currency_name: str | None = Field(default=None, max_length=50)
    currency_code: str | None = Field(default=None, max_length=3)
    is_default: bool | None = None
    settings: dict | None = None
    version: int = Field(ge=1)


class LoyaltyProgramRead(ORMBase):
    id: UUID
    tenant_id: UUID
    code: str
    name: str
    description: str | None
    status: ProgramStatus
    points_currency_name: str
    currency_code: str
    is_default: bool
    settings: dict | None
    version: int
    is_deleted: bool
    created_by: str | None
    updated_by: str | None
    created_at: datetime
    updated_at: datetime


class MembershipTierCreate(BaseModel):
    model_config = _FORBID

    program_id: UUID
    code: str = Field(max_length=50)
    name: str = Field(max_length=255)
    description: str | None = None
    rank: int = Field(default=0, ge=0)
    min_points: int = Field(default=0, ge=0)
    status: TierStatus = TierStatus.ACTIVE
    benefits: dict | None = None
    rules: dict | None = None


class MembershipTierUpdate(BaseModel):
    model_config = _FORBID

    name: str | None = Field(default=None, max_length=255)
    description: str | None = None
    rank: int | None = Field(default=None, ge=0)
    min_points: int | None = Field(default=None, ge=0)
    status: TierStatus | None = None
    benefits: dict | None = None
    rules: dict | None = None


class MembershipTierRead(ORMBase):
    id: UUID
    tenant_id: UUID
    program_id: UUID
    code: str
    name: str
    description: str | None
    rank: int
    min_points: int
    status: TierStatus
    benefits: dict | None
    rules: dict | None
    is_deleted: bool
    created_by: str | None
    updated_by: str | None
    created_at: datetime
    updated_at: datetime


class MemberCreate(BaseModel):
    model_config = _FORBID

    program_id: UUID
    display_name: str = Field(max_length=255)
    membership_number: str | None = Field(default=None, max_length=50)
    external_customer_ref: str | None = Field(default=None, max_length=100)
    email: str | None = Field(default=None, max_length=255)
    mobile: str | None = Field(default=None, max_length=50)
    status: MemberStatus = MemberStatus.PENDING
    tier_id: UUID | None = None
    profile: dict | None = None
    enroll: bool = False


class MemberUpdate(BaseModel):
    model_config = _FORBID

    display_name: str | None = Field(default=None, max_length=255)
    external_customer_ref: str | None = Field(default=None, max_length=100)
    email: str | None = Field(default=None, max_length=255)
    mobile: str | None = Field(default=None, max_length=50)
    status: MemberStatus | None = None
    tier_id: UUID | None = None
    profile: dict | None = None
    version: int = Field(ge=1)


class MemberEnrollRequest(BaseModel):
    model_config = _FORBID

    tier_id: UUID | None = None
    term_days: int | None = Field(default=None, ge=1, le=3650)
    expires_at: datetime | None = None
    reason: str | None = Field(default=None, max_length=500)


class MemberActivateRequest(BaseModel):
    model_config = _FORBID

    tier_id: UUID | None = None
    term_days: int | None = Field(default=None, ge=1, le=3650)
    expires_at: datetime | None = None
    reason: str | None = Field(default=None, max_length=500)


class MemberRenewRequest(BaseModel):
    model_config = _FORBID

    term_days: int | None = Field(default=None, ge=1, le=3650)
    expires_at: datetime | None = None
    reason: str | None = Field(default=None, max_length=500)


class MemberFreezeRequest(BaseModel):
    model_config = _FORBID

    reason: str = Field(max_length=500)


class MemberResumeRequest(BaseModel):
    model_config = _FORBID

    reason: str | None = Field(default=None, max_length=500)


class MemberCancelRequest(BaseModel):
    model_config = _FORBID

    reason: str = Field(max_length=500)


class MemberExpireRequest(BaseModel):
    model_config = _FORBID

    reason: str | None = Field(default=None, max_length=500)


class MemberTransferRequest(BaseModel):
    model_config = _FORBID

    target_program_id: UUID
    target_tier_id: UUID | None = None
    reason: str | None = Field(default=None, max_length=500)


class MemberRead(ORMBase):
    id: UUID
    tenant_id: UUID
    program_id: UUID
    membership_number: str
    external_customer_ref: str | None
    display_name: str
    email: str | None
    mobile: str | None
    status: MemberStatus
    tier_id: UUID | None
    enrolled_at: datetime | None
    activated_at: datetime | None
    membership_started_at: datetime | None
    membership_expires_at: datetime | None
    frozen_at: datetime | None
    freeze_reason: str | None
    cancelled_at: datetime | None
    cancel_reason: str | None
    expired_at: datetime | None
    transferred_to_member_id: UUID | None
    profile: dict | None
    version: int
    is_deleted: bool
    created_by: str | None
    updated_by: str | None
    created_at: datetime
    updated_at: datetime


class MembershipLifecycleEventRead(ORMBase):
    id: UUID
    tenant_id: UUID
    member_id: UUID
    action: str
    from_status: str
    to_status: str
    reason: str | None
    metadata_json: dict | None
    actor_user_id: str | None
    created_at: datetime


class PointAccountCreate(BaseModel):
    model_config = _FORBID

    program_id: UUID
    member_id: UUID
    account_number: str | None = Field(default=None, max_length=50)
    currency_name: str = Field(default="points", max_length=50)
    status: PointAccountStatus = PointAccountStatus.OPEN


class PointAccountUpdate(BaseModel):
    model_config = _FORBID

    status: PointAccountStatus | None = None
    currency_name: str | None = Field(default=None, max_length=50)
    version: int = Field(ge=1)


class PointAccountRead(ORMBase):
    id: UUID
    tenant_id: UUID
    program_id: UUID
    member_id: UUID
    account_number: str
    status: PointAccountStatus
    currency_name: str
    version: int
    is_deleted: bool
    created_by: str | None
    updated_by: str | None
    created_at: datetime
    updated_at: datetime


class RewardCreate(BaseModel):
    model_config = _FORBID

    program_id: UUID
    code: str = Field(max_length=50)
    name: str = Field(max_length=255)
    description: str | None = None
    reward_type: RewardType = RewardType.CUSTOM
    status: RewardStatus = RewardStatus.DRAFT
    points_cost: int = Field(default=0, ge=0)
    eligibility_rules: dict | None = None
    metadata_json: dict | None = None
    stock_limit: int | None = Field(default=None, ge=0)
    max_per_member: int | None = Field(default=None, ge=0)


class RewardUpdate(BaseModel):
    model_config = _FORBID

    name: str | None = Field(default=None, max_length=255)
    description: str | None = None
    reward_type: RewardType | None = None
    status: RewardStatus | None = None
    points_cost: int | None = Field(default=None, ge=0)
    eligibility_rules: dict | None = None
    metadata_json: dict | None = None
    stock_limit: int | None = Field(default=None, ge=0)
    max_per_member: int | None = Field(default=None, ge=0)


class RewardRead(ORMBase):
    id: UUID
    tenant_id: UUID
    program_id: UUID
    code: str
    name: str
    description: str | None
    reward_type: RewardType
    status: RewardStatus
    points_cost: int
    eligibility_rules: dict | None
    metadata_json: dict | None
    stock_limit: int | None
    redeemed_count: int
    max_per_member: int | None
    is_deleted: bool
    created_by: str | None
    updated_by: str | None
    created_at: datetime
    updated_at: datetime


class CampaignCreate(BaseModel):
    model_config = _FORBID

    program_id: UUID
    code: str = Field(max_length=50)
    name: str = Field(max_length=255)
    description: str | None = None
    status: CampaignStatus = CampaignStatus.DRAFT
    rules: dict | None = None
    starts_on: date | None = None
    ends_on: date | None = None


class CampaignUpdate(BaseModel):
    model_config = _FORBID

    name: str | None = Field(default=None, max_length=255)
    description: str | None = None
    status: CampaignStatus | None = None
    rules: dict | None = None
    starts_on: date | None = None
    ends_on: date | None = None
    bump_rule_version: bool = False


class CampaignRead(ORMBase):
    id: UUID
    tenant_id: UUID
    program_id: UUID
    code: str
    name: str
    description: str | None
    status: CampaignStatus
    rule_version: int
    rules: dict | None
    starts_on: date | None
    ends_on: date | None
    is_deleted: bool
    created_by: str | None
    updated_by: str | None
    created_at: datetime
    updated_at: datetime


class LoyaltyAuditLogRead(ORMBase):
    id: UUID
    tenant_id: UUID
    entity_type: str
    entity_id: UUID
    action: str
    actor_user_id: str | None
    changes: dict | None
    message: str | None
    created_at: datetime
