"""Phone number assignment models for Teams Phone Graph API responses.

These models represent phone number inventory and async operation data from Microsoft Graph API.
All models use `extra="forbid"` for strict contract validation to detect API changes.
"""

from datetime import datetime
from enum import Enum
from typing import Optional

from pydantic import BaseModel, ConfigDict, Field


class NumberType(str, Enum):
    """Phone number type in Teams Phone.

    Attributes:
        DIRECT_ROUTING: Direct routing phone number.
        CALLING_PLAN: Microsoft Calling Plan phone number.
        OPERATOR_CONNECT: Operator Connect phone number.
    """

    DIRECT_ROUTING = "directRouting"
    CALLING_PLAN = "callingPlan"
    OPERATOR_CONNECT = "operatorConnect"


class ActivationState(str, Enum):
    """Phone number activation state.

    Attributes:
        ACTIVATED: Number is active and ready for use.
        ASSIGNMENT_PENDING: Number assignment is in progress.
        ASSIGNMENT_FAILED: Number assignment failed.
        UPDATE_PENDING: Number update is in progress.
        UPDATE_FAILED: Number update failed.
    """

    ACTIVATED = "activated"
    ASSIGNMENT_PENDING = "assignmentPending"
    ASSIGNMENT_FAILED = "assignmentFailed"
    UPDATE_PENDING = "updatePending"
    UPDATE_FAILED = "updateFailed"


class AssignmentStatus(str, Enum):
    """Phone number assignment status.

    Attributes:
        UNASSIGNED: Number is not assigned to any user or resource.
        USER_ASSIGNED: Number is assigned to a user.
        CONFERENCE_ASSIGNED: Number is assigned to a conference bridge.
        VOICE_APPLICATION_ASSIGNED: Number is assigned to a voice application.
    """

    UNASSIGNED = "unassigned"
    USER_ASSIGNED = "userAssigned"
    CONFERENCE_ASSIGNED = "conferenceAssigned"
    VOICE_APPLICATION_ASSIGNED = "voiceApplicationAssigned"


class AssignmentCategory(str, Enum):
    """Phone number assignment category.

    Attributes:
        PRIMARY: Primary phone number for the user.
        PRIVATE: Private line number.
        ALTERNATE: Alternate phone number.
    """

    PRIMARY = "primary"
    PRIVATE = "private"
    ALTERNATE = "alternate"


class OperationStatus(str, Enum):
    """Async operation status from Graph API.

    Attributes:
        NOT_STARTED: Operation has not started.
        RUNNING: Operation is in progress.
        SUCCEEDED: Operation completed successfully.
        FAILED: Operation failed.
        SKIPPED: Operation was skipped.
        UNKNOWN_FUTURE_VALUE: Reserved for future values.
    """

    NOT_STARTED = "notStarted"
    RUNNING = "running"
    SUCCEEDED = "succeeded"
    FAILED = "failed"
    SKIPPED = "skipped"
    UNKNOWN_FUTURE_VALUE = "unknownFutureValue"


class OperationNumber(BaseModel):
    """Status of a phone number in an async operation.

    Attributes:
        resource_location: URL to the phone number resource.
        status: Current status of the operation for this number.
    """

    model_config = ConfigDict(extra="forbid", populate_by_name=True)

    resource_location: str = Field(alias="resourceLocation")
    status: OperationStatus


class AsyncOperation(BaseModel):
    """Async operation polling response from Graph API.

    Represents the response from polling a long-running phone number operation.

    Attributes:
        odata_context: OData context annotation from Graph API.
        odata_type: OData type annotation from Graph API.
        id: Unique identifier for the operation (not present in polling responses).
        created_date_time: When the operation was created.
        status: Overall status of the operation.
        numbers: Status of individual phone numbers in the operation.
    """

    model_config = ConfigDict(extra="forbid", populate_by_name=True)

    odata_context: Optional[str] = Field(alias="@odata.context", default=None)
    odata_type: Optional[str] = Field(alias="@odata.type", default=None)
    id: Optional[str] = Field(default=None)
    created_date_time: datetime = Field(alias="createdDateTime")
    status: OperationStatus
    numbers: list[OperationNumber] = Field(default=[])


class NumberAssignment(BaseModel):
    """Phone number assignment from Graph API.

    Represents a phone number in the tenant's inventory with its assignment details.

    Attributes:
        id: Unique identifier for the number assignment.
        telephone_number: Phone number in E.164 format.
        operator_id: ID of the operator providing the number.
        number_type: Type of the phone number (direct routing, calling plan, etc.).
        activation_state: Current activation state of the number.
        capabilities: List of capabilities (userAssignment, conferenceAssignment, etc.).
        location_id: ID of the emergency location.
        civic_address_id: ID of the civic address.
        network_site_id: ID of the network site.
        assignment_target_id: User or resource account object ID.
        assignment_category: Category of assignment (primary, private, alternate).
        assignment_status: Current assignment status.
        port_in_status: Status of port-in if applicable.
        iso_country_code: ISO country code (e.g., "US").
        city: City associated with the number.
        number_source: Source of the number (online, onPremises).
        supported_customer_actions: Actions the customer can perform on this number.
        reverse_number_lookup_options: Available reverse lookup options.
    """

    model_config = ConfigDict(extra="forbid", populate_by_name=True)

    id: str
    telephone_number: str = Field(alias="telephoneNumber")
    operator_id: Optional[str] = Field(alias="operatorId", default=None)
    number_type: NumberType = Field(alias="numberType")
    activation_state: ActivationState = Field(alias="activationState")
    capabilities: list[str]
    location_id: Optional[str] = Field(alias="locationId", default=None)
    civic_address_id: Optional[str] = Field(alias="civicAddressId", default=None)
    network_site_id: Optional[str] = Field(alias="networkSiteId", default=None)
    assignment_target_id: Optional[str] = Field(
        alias="assignmentTargetId", default=None
    )
    assignment_category: Optional[AssignmentCategory] = Field(
        alias="assignmentCategory", default=None
    )
    assignment_status: AssignmentStatus = Field(alias="assignmentStatus")
    port_in_status: Optional[str] = Field(alias="portInStatus", default=None)
    iso_country_code: Optional[str] = Field(alias="isoCountryCode", default=None)
    city: Optional[str] = Field(default=None)
    number_source: Optional[str] = Field(alias="numberSource", default=None)
    supported_customer_actions: list[str] = Field(
        alias="supportedCustomerActions", default=[]
    )
    reverse_number_lookup_options: list[str] = Field(
        alias="reverseNumberLookupOptions", default=[]
    )
