from __future__ import annotations

from datetime import datetime
from enum import Enum
from typing import Any, Dict, List, Optional

from pydantic import VERSION as PYDANTIC_VERSION

if PYDANTIC_VERSION.startswith("2."):
    from pydantic.v1 import BaseModel, Extra, Field, HttpUrl
else:
    from pydantic import BaseModel, Extra, Field, HttpUrl


class ProjectRunStatus(Enum):
    """
    Current status of a project run.
    """

    pending = "PENDING"
    running = "RUNNING"
    errored = "ERRORED"
    completed = "COMPLETED"
    killed = "KILLED"
    unabletoallocatekernel = "UNABLE_TO_ALLOCATE_KERNEL"


class Offset(BaseModel):
    class Config:
        extra = Extra.allow
        allow_mutation = False

    __root__: int = Field(
        default=..., description="Offset for paginated requests.", ge=0
    )


class PageSize(BaseModel):
    class Config:
        extra = Extra.allow
        allow_mutation = False

    __root__: int = Field(
        default=...,
        description="Number of results to fetch per page for paginated requests.",
        ge=1,
        le=100,
    )


class RunProjectRequestBody(BaseModel):
    class Config:
        extra = Extra.allow
        extra = Extra.forbid
        allow_mutation = False

    dry_run: Optional[bool] = Field(
        "false",
        alias="dryRun",
        description=(
            "If specified, perform a dry run without actually executing the project."
        ),
    )
    input_params: Optional[Dict[str, Any]] = Field(
        None,
        alias="inputParams",
        description="Optional input parameter value map for this project run.",
        example={"numeric_input_1": 123, "text_input_1": "Hello World"},
    )
    update_cache: Optional[bool] = Field(
        "false",
        alias="updateCache",
        description=(
            "When true, this run will update the cached state of the published app with"
            " the latest run results.\nAdditionally, any SQL cells that have caching"
            " enabled will be re-executed as part of this run. Note\nthat this cannot"
            " be set to true if custom input parameters are provided."
        ),
    )


class ProjectRunResponsePayload(BaseModel):
    """
    Response format returned by the runProject endpoint.
    """

    class Config:
        extra = Extra.allow
        allow_mutation = False

    project_id: str = Field(
        default=..., alias="projectId", description="Unique ID for a Hex project."
    )
    run_id: str = Field(
        default=..., alias="runId", description="Unique ID for a run of a Hex project."
    )
    run_status_url: HttpUrl = Field(
        default=...,
        alias="runStatusUrl",
        description="URL to query the status of the project run via the Hex API.",
    )
    run_url: HttpUrl = Field(
        default=...,
        alias="runUrl",
        description="URL to view the current progress of the project run in the Hex UI.",
    )
    trace_id: str = Field(
        default=...,
        alias="traceId",
        description=(
            "Hex trace ID to identify an API request. Provide this value to hex support"
            " with any API issues you encounter."
        ),
    )


class ProjectStatusResponsePayload(BaseModel):
    """
    Response format returned by the getRunStatus endpoint
    """

    class Config:
        extra = Extra.allow
        allow_mutation = False

    elapsed_time: float = Field(
        default=...,
        alias="elapsedTime",
        description="Total elapsed time for the project run in milliseconds.",
    )
    end_time: Optional[datetime] = Field(
        default=None,
        alias="endTime",
        description="UTC timestamp of when the project run finished.",
    )
    project_id: str = Field(
        default=..., alias="projectId", description="Unique ID for a Hex project."
    )
    run_id: str = Field(
        default=..., alias="runId", description="Unique ID for a run of a Hex project."
    )
    run_url: HttpUrl = Field(
        default=...,
        alias="runUrl",
        description="URL to view the current progress of the project run in the Hex UI.",
    )
    start_time: datetime = Field(
        default=...,
        alias="startTime",
        description="UTC timestamp of when the project run started.",
    )
    status: ProjectRunStatus
    trace_id: str = Field(
        default=...,
        alias="traceId",
        description=(
            "Hex trace ID to identify an API request. Provide this value to hex support"
            " with any API issues you encounter."
        ),
    )


class ProjectRunsResponsePayload(BaseModel):
    """
    Response format returned by the getProjectRuns endpoint.
    """

    class Config:
        extra = Extra.allow
        allow_mutation = False

    next_page: Optional[HttpUrl] = Field(
        None,
        alias="nextPage",
        description="URL to fetch the next page of results for a paginated API request.",
    )
    previous_page: Optional[HttpUrl] = Field(
        None,
        alias="previousPage",
        description="URL to fetch the previous page of results for a paginated API request.",
    )
    runs: List[ProjectStatusResponsePayload] = Field(
        default=...,
        description=(
            "Array of run status payloads in the same format returned by the"
            " `GetRunStatus` endpoint."
        ),
    )
    trace_id: str = Field(
        default=...,
        alias="traceId",
        description=(
            "Hex trace ID to identify an API request. Provide this value to hex support"
            " with any API issues you encounter."
        ),
    )
