import uuid
from datetime import datetime
from typing import TYPE_CHECKING, List, Optional, Union

if TYPE_CHECKING:
    from letta.orm.llm_batch_items import LLMBatchItem
    from letta.orm.organization import Organization

from anthropic.types.beta.messages import BetaMessageBatch
from sqlalchemy import DateTime, ForeignKey, Index, String
from sqlalchemy.orm import Mapped, mapped_column, relationship

from letta.orm.custom_columns import CreateBatchResponseColumn, PollBatchResponseColumn
from letta.orm.mixins import OrganizationMixin
from letta.orm.sqlalchemy_base import SqlalchemyBase
from letta.schemas.enums import JobStatus, ProviderType
from letta.schemas.llm_batch_job import LLMBatchJob as PydanticLLMBatchJob


class LLMBatchJob(SqlalchemyBase, OrganizationMixin):
    """Represents a single LLM batch request made to a provider like Anthropic"""

    __tablename__ = "llm_batch_job"
    __table_args__ = (
        Index("ix_llm_batch_job_created_at", "created_at"),
        Index("ix_llm_batch_job_status", "status"),
    )

    __pydantic_model__ = PydanticLLMBatchJob

    # TODO: We want to migrate all the ORM models to do this, so we will need to move this to the SqlalchemyBase
    # TODO: Some still rely on the Pydantic object to do this
    id: Mapped[str] = mapped_column(String, primary_key=True, default=lambda: f"batch_req-{uuid.uuid4()}")

    status: Mapped[JobStatus] = mapped_column(String, default=JobStatus.created, doc="The current status of the batch.")

    llm_provider: Mapped[ProviderType] = mapped_column(String, doc="LLM provider used (e.g., 'Anthropic')")

    create_batch_response: Mapped[Union[BetaMessageBatch]] = mapped_column(
        CreateBatchResponseColumn, doc="Full JSON response from initial batch creation"
    )
    latest_polling_response: Mapped[Union[BetaMessageBatch]] = mapped_column(
        PollBatchResponseColumn, nullable=True, doc="Last known polling result from LLM provider"
    )

    last_polled_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True, doc="Last time we polled the provider for status"
    )

    letta_batch_job_id: Mapped[str] = mapped_column(
        String, ForeignKey("jobs.id", ondelete="CASCADE"), nullable=False, doc="ID of the Letta batch job"
    )

    organization: Mapped["Organization"] = relationship("Organization", back_populates="llm_batch_jobs")
    items: Mapped[List["LLMBatchItem"]] = relationship("LLMBatchItem", back_populates="batch", lazy="selectin")
