from __future__ import annotations
from typing import Optional, List, Any
from pydantic import BaseModel, field_validator
from datetime import datetime


# ---------------------------------------------------------------------------
# Price Groups
# ---------------------------------------------------------------------------

class PriceGroupCreate(BaseModel):
    name: str
    description: Optional[str] = None
    color: Optional[str] = None
    is_active: bool = False
    auto_enable_time: Optional[str] = None   # "HH:MM"
    auto_disable_time: Optional[str] = None  # "HH:MM"
    auto_days: Optional[List[int]] = None    # [0..6] Mon=0


class PriceGroupUpdate(PriceGroupCreate):
    pass


class PriceGroupOut(BaseModel):
    id: int
    name: str
    description: Optional[str]
    color: Optional[str]
    is_active: bool
    auto_enable_time: Optional[str]
    auto_disable_time: Optional[str]
    auto_days: Optional[List[int]]
    created_at: Optional[datetime]

    model_config = {"from_attributes": True}

    @field_validator("is_active", mode="before")
    @classmethod
    def coerce_bool(cls, v):
        return bool(v)

    @field_validator("auto_days", mode="before")
    @classmethod
    def parse_auto_days(cls, v):
        if isinstance(v, str):
            import json
            try:
                return json.loads(v)
            except Exception:
                return None
        return v


# ---------------------------------------------------------------------------
# Price Modifier Conditions
# ---------------------------------------------------------------------------

class ConditionIn(BaseModel):
    condition_type: str
    params: dict = {}


class ConditionOut(BaseModel):
    id: int
    condition_type: str
    params: dict

    model_config = {"from_attributes": True}

    @field_validator("params", mode="before")
    @classmethod
    def parse_params(cls, v):
        if isinstance(v, str):
            import json
            try:
                return json.loads(v)
            except Exception:
                return {}
        return v or {}


# ---------------------------------------------------------------------------
# Price Modifier Targets
# ---------------------------------------------------------------------------

class ModifierTargetIn(BaseModel):
    target_type: str             # 'all'|'item'|'category'|'prep_zone'|'tag'
    target_id: Optional[int] = None
    target_tag: Optional[str] = None
    target_ids: Optional[List[int]] = None
    target_tags: Optional[List[str]] = None


class ModifierTargetOut(BaseModel):
    id: int
    target_type: str
    target_id: Optional[int]
    target_tag: Optional[str]
    target_ids: Optional[List[int]] = None
    target_tags: Optional[List[str]] = None

    model_config = {"from_attributes": True}

    @field_validator("target_ids", "target_tags", mode="before")
    @classmethod
    def parse_json_list(cls, v):
        if isinstance(v, str):
            import json
            return json.loads(v)
        return v


# ---------------------------------------------------------------------------
# Price Modifiers
# ---------------------------------------------------------------------------

class PriceModifierCreate(BaseModel):
    name: str
    description: Optional[str] = None
    color: Optional[str] = None
    is_active: bool = True
    is_favorite: bool = False
    allow_stack: bool = False
    sort_order: int = 0
    scope: str = "global"                 # 'item' | 'global'
    item_id: Optional[int] = None
    action_type: str                      # 'set' | 'add_amount' | 'add_percent'
    action_value: float
    round_to: Optional[str] = None        # '0.05'|'0.10'|'0.20'|'0.50'|'x.99'|'x.00'
    conditions: List[ConditionIn] = []
    targets: List[ModifierTargetIn] = []  # only relevant for scope='global'


class PriceModifierUpdate(PriceModifierCreate):
    pass


class PriceModifierOut(BaseModel):
    id: int
    name: str
    description: Optional[str]
    color: Optional[str]
    is_active: bool
    is_favorite: bool
    allow_stack: bool
    sort_order: int
    scope: str
    item_id: Optional[int]
    action_type: str
    action_value: float
    round_to: Optional[str]
    conditions: List[ConditionOut]
    targets: List[ModifierTargetOut]
    created_at: Optional[datetime]
    updated_at: Optional[datetime]

    model_config = {"from_attributes": True}

    @field_validator("is_active", "is_favorite", "allow_stack", mode="before")
    @classmethod
    def coerce_bool(cls, v):
        return bool(v)


class PriceModifierReorderItem(BaseModel):
    id: int
    sort_order: int


class PriceModifierReorderRequest(BaseModel):
    items: List[PriceModifierReorderItem]


# ---------------------------------------------------------------------------
# Deals
# ---------------------------------------------------------------------------

class DealTargetIn(BaseModel):
    target_type: str             # 'item'|'category'|'tag'|'any'
    target_id: Optional[int] = None
    target_tag: Optional[str] = None
    target_ids: Optional[List[int]] = None
    target_tags: Optional[List[str]] = None


class DealTargetOut(BaseModel):
    id: int
    target_type: str
    target_id: Optional[int]
    target_tag: Optional[str]
    target_ids: Optional[List[int]] = None
    target_tags: Optional[List[str]] = None

    model_config = {"from_attributes": True}

    @field_validator("target_ids", "target_tags", mode="before")
    @classmethod
    def parse_json_list(cls, v):
        if isinstance(v, str):
            import json
            return json.loads(v)
        return v


class DealCreate(BaseModel):
    name: str
    description: Optional[str] = None
    color: Optional[str] = None
    is_active: bool = True
    sort_order: int = 0
    action_type: str
    # Action payload — which fields are set depends on action_type
    action_modifier_id: Optional[int] = None        # for apply_modifier
    action_value: Optional[float] = None             # for set_price / add_amount / add_percent
    action_free_item_id: Optional[int] = None        # for free_item
    action_free_target_type: Optional[str] = None    # for free_choice: 'item'|'category'|'tag'
    action_free_target_ids: Optional[List[Any]] = None  # for free_choice
    action_free_quantity: int = 1
    conditions: List[ConditionIn] = []
    targets: List[DealTargetIn] = []


class DealUpdate(DealCreate):
    pass


class DealOut(BaseModel):
    id: int
    name: str
    description: Optional[str]
    color: Optional[str]
    is_active: bool
    sort_order: int
    action_type: str
    action_modifier_id: Optional[int]
    action_value: Optional[float]
    action_free_item_id: Optional[int]
    action_free_target_type: Optional[str]
    action_free_target_ids: Optional[List[Any]]
    action_free_quantity: int
    conditions: List[ConditionOut]
    targets: List[DealTargetOut]
    created_at: Optional[datetime]

    model_config = {"from_attributes": True}

    @field_validator("is_active", mode="before")
    @classmethod
    def coerce_bool(cls, v):
        return bool(v)

    @field_validator("action_free_target_ids", mode="before")
    @classmethod
    def parse_target_ids(cls, v):
        if isinstance(v, str):
            import json
            try:
                return json.loads(v)
            except Exception:
                return None
        return v


# ---------------------------------------------------------------------------
# Waiter Discount Settings
# ---------------------------------------------------------------------------

class WaiterDiscountSettingsIn(BaseModel):
    can_apply_discounts: bool = False
    max_discount_percent: Optional[float] = None
    max_discount_amount: Optional[float] = None
    max_total_value_shift: Optional[float] = None
    max_total_value_workday: Optional[float] = None
    max_items_per_shift: Optional[int] = None
    max_items_per_workday: Optional[int] = None
    max_items_per_order: Optional[int] = None


class WaiterDiscountSettingsOut(WaiterDiscountSettingsIn):
    id: int
    user_id: int

    model_config = {"from_attributes": True}

    @field_validator("can_apply_discounts", mode="before")
    @classmethod
    def coerce_bool(cls, v):
        return bool(v)


# ---------------------------------------------------------------------------
# Price Event Log
# ---------------------------------------------------------------------------

class PriceEventOut(BaseModel):
    id: int
    order_id: int
    order_item_id: Optional[int]
    event_type: str
    modifier_id: Optional[int]
    deal_id: Optional[int]
    price_before: Optional[float]
    price_after: Optional[float]
    delta_amount: Optional[float]
    applied_by_user_id: Optional[int]
    waiter_note: Optional[str]
    conditions_snapshot: Optional[dict]
    selected_item_ids: Optional[List[int]]
    applied_at: datetime
    # Resolved names (joined at query time)
    modifier_name: Optional[str] = None
    deal_name: Optional[str] = None
    applied_by_username: Optional[str] = None

    model_config = {"from_attributes": True}

    @field_validator("conditions_snapshot", mode="before")
    @classmethod
    def parse_snapshot(cls, v):
        if isinstance(v, str):
            import json
            try:
                return json.loads(v)
            except Exception:
                return None
        return v

    @field_validator("selected_item_ids", mode="before")
    @classmethod
    def parse_item_ids(cls, v):
        if isinstance(v, str):
            import json
            try:
                return json.loads(v)
            except Exception:
                return None
        return v


# ---------------------------------------------------------------------------
# Waiter discount apply (PWA-facing)
# ---------------------------------------------------------------------------

class ApplyDiscountRequest(BaseModel):
    item_ids: List[int]
    discount_percent: float   # e.g. 10.0 = 10%; final price rounds to nearest 0.10
    note: Optional[str] = None


class ApplyDiscountResponse(BaseModel):
    applied: List[dict]       # [{item_id, price_before, price_after, delta}]
    remaining_budget_shift: Optional[float] = None
    remaining_budget_workday: Optional[float] = None


# ---------------------------------------------------------------------------
# Deal offer response (returned on add_items when deals are newly triggered)
# ---------------------------------------------------------------------------

class DealOfferOut(BaseModel):
    deal_id: int
    deal_name: str
    action_type: str
    free_item_id: Optional[int] = None
    free_item_name: Optional[str] = None
    free_choices: List[dict] = []   # [{id, name}]
    free_quantity: int = 1
    target_order_item_id: Optional[int] = None
    price_before: Optional[float] = None
    price_after: Optional[float] = None


# ---------------------------------------------------------------------------
# Deal offer accept (waiter confirms a deal)
# ---------------------------------------------------------------------------

class AcceptDealOfferRequest(BaseModel):
    deal_id: int
    selected_product_ids: Optional[List[int]] = None  # for free_choice


class DismissDealOfferRequest(BaseModel):
    deal_id: int
