"""
SellerLegend API PPC Resource Client

Handles PPC (Pay-Per-Click) advertising data endpoints for Sponsored Products,
Sponsored Brands, and Sponsored Display campaigns.
"""

from typing import Dict, Any, Optional, Union, Literal
from datetime import datetime, date
from ..base import BaseClient
from ..validators import (
    validate_date, validate_date_range, validate_enum, validate_currency,
    validate_account_params, clean_params, ValidationError
)

# Valid PPC types
PPC_TYPES = ['sp', 'sb', 'sd']

# Valid entity types per PPC type
PPC_ENTITY_TYPES = {
    'sp': ['campaigns', 'ad-groups', 'products', 'products-by-campaign', 'ad-keywords', 'search-terms', 'targets'],
    'sb': ['campaigns', 'ad-groups', 'ad-keywords'],
    'sd': ['campaigns', 'ad-groups', 'products'],
}

# Valid per_page values for PPC
PPC_PER_PAGE_VALUES = [10, 20, 50, 100, 250, 500, 1000, 2000]

# Valid aggregate modes
AGGREGATE_MODES = ['summary', 'daily']

# Valid filter condition types and their allowed conditions
FILTER_TYPES = {
    'text': ['contains', 'is', 'is_not', 'starts_with', 'ends_with', 'is_empty', 'regexp', 'is_null', 'not_null'],
    'number': ['>', '<', '>=', '<=', '=', 'between', 'is_null', 'not_null'],
    'select': ['in', 'not_in', 'is_null', 'not_null'],
    'date': ['between', 'greater_than', 'less_than', 'equal_to', 'is_null', 'not_null'],
    'bool': ['true', 'false', 'is_null', 'not_null'],
}


class PpcClient:
    """Client for PPC (Pay-Per-Click) advertising data endpoints."""

    def __init__(self, base_client: BaseClient):
        """
        Initialize PPC client.

        Args:
            base_client: Base API client instance
        """
        self.client = base_client

    def get_list(
        self,
        ppc_type: Literal["sp", "sb", "sd"],
        entity_type: str,
        per_page: int = 100,
        currency: str = "USD",
        aggregate_mode: Optional[Literal["summary", "daily"]] = None,
        start_date: Optional[Union[str, date, datetime]] = None,
        end_date: Optional[Union[str, date, datetime]] = None,
        campaign_id: Optional[str] = None,
        ad_group_id: Optional[str] = None,
        custom_filter: Optional[Dict[str, Any]] = None,
        account_title: Optional[str] = None,
        seller_id: Optional[str] = None,
        marketplace_id: Optional[str] = None,
        group_title: Optional[str] = None,
        filter_by: Optional[Literal["sku", "asin", "parent_asin"]] = None,
        filter_value: Optional[str] = None,
        **kwargs
    ) -> Dict[str, Any]:
        """
        Get PPC advertising data for campaigns, ad groups, keywords, etc.

        Retrieves PPC data across Sponsored Products (sp), Sponsored Brands (sb),
        and Sponsored Display (sd) advertising types.

        Args:
            ppc_type: PPC advertising type - "sp" (Sponsored Products),
                "sb" (Sponsored Brands), or "sd" (Sponsored Display)
            entity_type: Entity type to retrieve. Valid values depend on ppc_type:
                - sp: campaigns, ad-groups, products, products-by-campaign,
                      ad-keywords, search-terms, targets
                - sb: campaigns, ad-groups, ad-keywords
                - sd: campaigns, ad-groups, products
            per_page: Number of results per page (10, 20, 50, 100, 250, 500, 1000, 2000)
            currency: Currency code for monetary values (e.g., "USD", "EUR")
            aggregate_mode: Data aggregation mode - "summary" (default) or "daily"
            start_date: Start date for data range (defaults to last 7 days)
            end_date: End date for data range (defaults to today)
            campaign_id: Filter by specific campaign ID
            ad_group_id: Filter by specific ad group ID
            custom_filter: Advanced column-level filtering. Dict of column_name to
                filter spec with type, condition, and value. Example:
                {"impressions": {"type": "number", "condition": ">", "value": 100}}
            account_title: Filter by account title
            seller_id: Amazon seller ID (requires marketplace_id)
            marketplace_id: Amazon marketplace ID (requires seller_id)
            group_title: Filter by account group
            filter_by: Legacy filter field ("sku", "asin", "parent_asin")
            filter_value: Legacy filter value (requires filter_by)
            **kwargs: Additional parameters

        Returns:
            Paginated PPC data with campaign/ad group/keyword metrics

        Raises:
            ValidationError: If parameters are invalid
        """
        # Validate ppc_type
        validate_enum(ppc_type, PPC_TYPES, "ppc_type")

        # Validate entity_type for the given ppc_type
        valid_entities = PPC_ENTITY_TYPES.get(ppc_type, [])
        validate_enum(entity_type, valid_entities, "entity_type")

        # Validate per_page
        validate_enum(per_page, PPC_PER_PAGE_VALUES, "per_page")

        # Validate currency
        currency = validate_currency(currency)

        # Validate aggregate_mode
        if aggregate_mode:
            validate_enum(aggregate_mode, AGGREGATE_MODES, "aggregate_mode")

        # Validate dates
        start_date = validate_date(start_date, "start_date")
        end_date = validate_date(end_date, "end_date")
        if start_date and end_date:
            validate_date_range(start_date, end_date)

        # Validate custom_filter structure
        if custom_filter:
            self._validate_custom_filter(custom_filter)

        # Validate filter_by/filter_value pair
        if filter_by and not filter_value:
            raise ValidationError("filter_value is required when filter_by is specified")
        if filter_value and not filter_by:
            raise ValidationError("filter_by is required when filter_value is specified")

        params = {
            "ppc_type": ppc_type,
            "entity_type": entity_type,
            "per_page": per_page,
            "currency": currency,
            "aggregate_mode": aggregate_mode,
            "start_date": start_date,
            "end_date": end_date,
            "campaign_id": campaign_id,
            "ad_group_id": ad_group_id,
            "custom_filter": custom_filter,
            "account_title": account_title,
            "seller_id": seller_id,
            "marketplace_id": marketplace_id,
            "group_title": group_title,
            "filter_by": filter_by,
            "filter_value": filter_value,
        }
        params.update(kwargs)

        # Validate account params
        validate_account_params(**params)

        # Clean and send request
        params = clean_params(params)
        return self.client.get("ppc/get-list", params=params)

    @staticmethod
    def _validate_custom_filter(custom_filter: Dict[str, Any]) -> None:
        """
        Validate custom_filter structure.

        Args:
            custom_filter: Filter dict to validate

        Raises:
            ValidationError: If filter structure is invalid
        """
        if not isinstance(custom_filter, dict):
            raise ValidationError("custom_filter must be a dictionary")

        for column_name, filter_spec in custom_filter.items():
            if not isinstance(filter_spec, dict):
                raise ValidationError(f"custom_filter.{column_name} must be a dictionary")

            if 'type' not in filter_spec:
                raise ValidationError(f"custom_filter.{column_name} requires 'type'")

            filter_type = filter_spec['type']
            if filter_type not in FILTER_TYPES:
                valid_types = ', '.join(FILTER_TYPES.keys())
                raise ValidationError(
                    f"custom_filter.{column_name}.type must be one of: {valid_types}"
                )

            if 'condition' not in filter_spec:
                raise ValidationError(f"custom_filter.{column_name} requires 'condition'")

            condition = filter_spec['condition']
            valid_conditions = FILTER_TYPES[filter_type]
            if condition not in valid_conditions:
                raise ValidationError(
                    f"custom_filter.{column_name}.condition must be one of: {', '.join(valid_conditions)}"
                )

    @staticmethod
    def get_valid_entity_types(ppc_type: str) -> list:
        """
        Get valid entity types for a given PPC type.

        Args:
            ppc_type: PPC type ("sp", "sb", or "sd")

        Returns:
            List of valid entity type strings

        Raises:
            ValidationError: If ppc_type is invalid
        """
        validate_enum(ppc_type, PPC_TYPES, "ppc_type")
        return PPC_ENTITY_TYPES[ppc_type]
