from typing import Any, ClassVar, Literal

from cognite_toolkit._cdf_tk.client._resource_base import (
    BaseModelObject,
    ResponseResource,
    UpdatableRequestResource,
)
from cognite_toolkit._cdf_tk.client._types import Metadata

from .identifiers import ExternalId


class RawTable(BaseModelObject):
    db_name: str
    table_name: str


class Contact(BaseModelObject):
    name: str | None = None
    email: str | None = None
    role: str | None = None
    send_notification: bool | None = None


class NotificationConfig(BaseModelObject):
    allowed_not_seen_range_in_minutes: int | None = None


class ExtractionPipeline(BaseModelObject):
    external_id: str
    name: str
    description: str | None = None
    data_set_id: int
    raw_tables: list[RawTable] | None = None
    schedule: str | None = None
    contacts: list[Contact] | None = None
    metadata: Metadata | None = None
    source: str | None = None
    documentation: str | None = None
    notification_config: NotificationConfig | None = None
    created_by: str | None = None

    def as_id(self) -> ExternalId:
        return ExternalId(external_id=self.external_id)


class ExtractionPipelineRequest(ExtractionPipeline, UpdatableRequestResource):
    container_fields: ClassVar[frozenset[str]] = frozenset({"raw_tables", "contacts", "metadata"})
    non_nullable_fields: ClassVar[frozenset[str]] = frozenset(
        {"documentation", "source", "notification_config", "schedule", "description"}
    )

    def as_update(self, mode: Literal["patch", "replace"]) -> dict[str, Any]:
        update = super().as_update(mode)
        # createdBy cannot be updated.
        update["update"].pop("createdBy", None)
        return update


class ExtractionPipelineResponse(ExtractionPipeline, ResponseResource[ExtractionPipelineRequest]):
    id: int
    created_time: int
    last_updated_time: int

    @classmethod
    def request_cls(cls) -> type[ExtractionPipelineRequest]:
        return ExtractionPipelineRequest
