"""
WARNING: This file is copied from trusted/python-libs/dq-media-dcr-api/dq_media_dcr_api.
DO NOT EDIT THIS FILE DIRECTLY - make changes in the source repository instead and run the copy_init.py script.
"""

"""
This module defines the DCR API models for the types used by dq-media-dcr.
To ensure backwards compatibility, new fields should be added as optional with a default value of None.
Marking a field as optional is not enough, a default **must** be provided. Failure to do so will result in a validation error
on the client side.
"""

import warnings
from enum import Enum
from typing import List, Literal, Optional, Union, Dict, Any, Sequence
from datetime import datetime
from pydantic import BaseModel, Field, conint

# Suppress Pydantic shadowing warnings
warnings.filterwarnings("ignore", message="Field name.*shadows an attribute.*BaseModel")


class AudienceKind(str, Enum):
    SEED = "SEED"
    CUSTOM = "CUSTOM"


class SeedAudience(BaseModel):
    kind: AudienceKind
    audienceType: str
    audienceSize: Optional[int] = None
    createdAt: datetime
    isEmpty: bool


class AudienceReference1(BaseModel):
    kind: Literal["BASE"]


class AudienceReference2(BaseModel):
    id: str
    kind: Literal["CUSTOM"]


class AudienceReference3(BaseModel):
    audienceType: str
    kind: Literal["SEED"]


class SeedAudienceReference(BaseModel):
    audienceType: str


AudienceReference = Union[AudienceReference1, AudienceReference2, AudienceReference3]


class CustomAudienceDefinition1(BaseModel):
    excludeSeedAudience: Optional[bool] = None
    kind: Literal["LOOKALIKE"]
    reach: int
    sourceRef: AudienceReference


CombineOperator = Literal["INTERSECT", "UNION", "DIFF"]
FilterOperator = Literal[
    "CONTAINS_ANY_OF", "CONTAINS_NONE_OF", "CONTAINS_ALL_OF", "EMPTY", "NOT_EMPTY"
]


class AudienceFilter(BaseModel):
    attribute: str
    operator: FilterOperator
    values: Optional[Sequence[str]] = None


BooleanOp = Literal["AND", "OR"]


class AudienceFilters(BaseModel):
    booleanOp: BooleanOp
    filters: Sequence[AudienceFilter]


class AudienceCombinator(BaseModel):
    filters: Optional[AudienceFilters] = None
    operator: CombineOperator
    sourceRef: AudienceReference


class CustomAudienceDefinition2(BaseModel):
    combine: Optional[Sequence[AudienceCombinator]] = None
    filters: Optional[AudienceFilters] = None
    kind: Literal["RULE_BASED"]
    sourceRef: AudienceReference


class CustomAudienceDefinition3(BaseModel):
    kind: Literal["REMARKETING"]
    seedAudienceRef: SeedAudienceReference


class StalenessWarnings(BaseModel):
    missingCustomAudiences: Optional[Sequence[str]] = []
    missingFilterAttributes: Optional[Sequence[str]] = []
    missingFilterValues: Optional[Sequence[str]] = []
    missingSeedAudiences: Optional[Sequence[str]] = []


class CustomAudience(BaseModel):
    createdAt: str
    createdBy: str
    definition: Union[CustomAudienceDefinition1, CustomAudienceDefinition2, CustomAudienceDefinition3]
    doesAudienceDependOnLookalikeAudience: Optional[bool] = None
    id: str
    kind: AudienceKind = AudienceKind.CUSTOM
    name: str
    sharedWith: Optional[Sequence[str]] = None
    stalenessWarnings: Optional[StalenessWarnings] = None


class GetCustomAudiencesResult(BaseModel):
    audiences: List[CustomAudience]


class GetSeedAudiencesResult(BaseModel):
    audiences: List[SeedAudience]


class ValueType(str, Enum):
    NUMERIC_RANGE = "NUMERIC_RANGE"
    CATEGORICAL = "CATEGORICAL"


class FilterType(str, Enum):
    CONTAINS_NONE_OF = "CONTAINS_NONE_OF"
    CONTAINS_ANY_OF = "CONTAINS_ANY_OF"
    CONTAINS_ALL_OF = "CONTAINS_ALL_OF"
    EMPTY = "EMPTY"
    NOT_EMPTY = "NOT_EMPTY"


class AttributeDefinition(BaseModel):
    values: List[Union[str, int, float]]
    value_type: ValueType
    filters: List[FilterType]


class DataAttributesResult(BaseModel):
    attributes: Dict[str, AttributeDefinition]


class AggregationColumn(BaseModel):
    column: str
    possible_values: List[str]


class Aggregation(BaseModel):
    id: str
    aggregation: List[AggregationColumn]
    audience_type: str
    columns: List[str]
    rows: List[List[Any]]


class ComputeInsightsAudience(BaseModel):
    audience_type: str
    aggregations: List[Aggregation]


class ComputeInsightsResult(BaseModel):
    total_publisher: Optional[int] = (
        None  # Optional because it depends on hide_absolute_values_from_insights
    )
    audiences: List[ComputeInsightsAudience]


class OverlapStatistic(BaseModel):
    audience_type: str
    advertiser_size: Optional[int] = None  # Optional because it might be hidden
    advertiser_is_empty: bool
    overlap_size: Optional[int] = None  # Optional because it might be hidden
    match_rate: Optional[float] = None  # Optional because it might be hidden


class OverlapStatisticsResult(BaseModel):
    overlap_statistics: List[OverlapStatistic]


class RocCurvePoint(BaseModel):
    """Represents a single point on the ROC curve"""

    tpr: float
    fpr: float


class FilteredAudienceQuality(BaseModel):
    """Quality metrics for a filtered audience"""

    roc_curve: Optional[RocCurvePoint] = None


class FilteredAudience(BaseModel):
    """Represents a filtered audience at a specific reach percentage"""

    reach: int
    size: int
    quality: FilteredAudienceQuality


class RocCurveData(BaseModel):
    """Complete ROC curve data including AUC and test set information"""

    auc: float
    fpr: List[float]
    tpr: List[float]
    reach: List[float]
    test_set_size: int
    test_set_positive_examples_size: int


class QualityMetrics(BaseModel):
    """Overall quality metrics including complete ROC curve data"""

    roc_curve: RocCurveData


class LookalikeAudienceStatisticsResult(BaseModel):
    """Root model representing the complete lookalike audience statistics"""

    addressable_audience_size: int
    seed_audience_size: int
    filtered_audiences: List[FilteredAudience]
    quality: QualityMetrics


class CellLocation(BaseModel):
    column: int = Field(ge=0)
    row: int = Field(ge=0)


class CellValidationErrorCode(str, Enum):
    EMPTY_CELL = "EMPTY_CELL"
    INTERNAL_VALIDATION_ERROR = "INTERNAL_VALIDATION_ERROR"
    INVALID_NUMBER_FORMAT = "INVALID_NUMBER_FORMAT"
    INVALID_INTEGER_FORMAT = "INVALID_INTEGER_FORMAT"
    INVALID_EMAIL_FORMAT = "INVALID_EMAIL_FORMAT"
    INVALID_ISO_DATE_FORMAT = "INVALID_ISO_DATE_FORMAT"
    INVALID_PHONE_E164_NUMBER = "INVALID_PHONE_E164_NUMBER"
    INVALID_FLOAT_FORMAT = "INVALID_FLOAT_FORMAT"
    INVALID_SHA256_HEX_FORMAT = "INVALID_SHA256_HEX_FORMAT"
    INVALID_NUMERIC_RANGE = "INVALID_NUMERIC_RANGE"


class CellValidationError(BaseModel):
    code: CellValidationErrorCode
    location: CellLocation
    message: str


class DuplicationValidationErrorCode(str, Enum):
    DUPLICATE_VALUES = "DUPLICATE_VALUES"


class MultiColumnLocation(BaseModel):
    columns: Sequence[conint(ge=0)]
    row: int = Field(ge=0)


class DuplicationValidationError(BaseModel):
    code: DuplicationValidationErrorCode
    location: MultiColumnLocation


class SchemaValidationErrorCode(str, Enum):
    INTERNAL_VALIDATION_ERROR = "INTERNAL_VALIDATION_ERROR"
    DUPLICATE_VALUES = "DUPLICATE_VALUES"
    NOT_ENOUGH_COLUMNS_PROVIDED = "NOT_ENOUGH_COLUMNS_PROVIDED"
    TOO_MANY_COLUMNS_PROVIDED = "TOO_MANY_COLUMNS_PROVIDED"
    EMPTY_FILE = "EMPTY_FILE"


class SchemaValidationError(BaseModel):
    code: SchemaValidationErrorCode
    message: str
    row: int = Field(ge=0)


class TableValidationErrorCode(str, Enum):
    EMPTY_FILE = "EMPTY_FILE"
    INVALID_NUMBER_OF_ROWS = "INVALID_NUMBER_OF_ROWS"


class TableValidationError(BaseModel):
    code: TableValidationErrorCode
    message: str


class ValidatedColumnV0(BaseModel):
    column: int = Field(ge=0)
    numErrorsTotal: int = Field(ge=0)
    recordedErrors: Sequence[CellValidationError]


class ValidatedSchemaV0(BaseModel):
    numErrorsTotal: int = Field(ge=0)
    recordedErrors: Sequence[SchemaValidationError]


class ValidatedTableV0(BaseModel):
    numErrorsTotal: int = Field(ge=0)
    recordedErrors: Sequence[TableValidationError]


class ValidatedUniqueness(BaseModel):
    numErrorsTotal: int = Field(ge=0)
    recordedErrors: Sequence[DuplicationValidationError]


class ValidationOutcome(str, Enum):
    PASSED = "PASSED"
    FAILED = "FAILED"


class DropInvalidRows(BaseModel):
    numInvalidRowsDropped: int = Field(ge=0)


class ValidationReportV0(BaseModel):
    columns: Sequence[ValidatedColumnV0]
    dropInvalidRows: Optional[DropInvalidRows] = None
    numInvalidRowsTotal: int = Field(ge=0)
    numRowsTotal: int = Field(default=0, ge=0)
    originalFileSizeBytes: Optional[int] = Field(None, ge=0)
    outcome: ValidationOutcome
    schema: ValidatedSchemaV0  # Shadows BaseModel.schema
    table: ValidatedTableV0
    uniqueness: Optional[ValidatedUniqueness] = None


class ValidationReport(BaseModel):
    report: ValidationReportV0
    version: str = Field(..., enum=["v0"])
