import enum
from datetime import datetime

from sqlalchemy import BigInteger, DateTime, ForeignKey, Integer, String, Text
from sqlalchemy import Enum as SAEnum
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.types import JSON

from app.models.base import BaseModel


class InstanceDiskAddonStatus(str, enum.Enum):
    PENDING = "pending"
    ACTIVE = "active"
    FAILED = "failed"
    REFUNDED = "refunded"
    DELETED = "deleted"


class InstanceDiskAddon(BaseModel):
    """Elastic data disk billing record attached to an instance."""

    __tablename__ = "instance_disk_addons"

    user_id: Mapped[int] = mapped_column(
        BigInteger, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True
    )
    instance_id: Mapped[int] = mapped_column(
        ForeignKey("instances.id", ondelete="CASCADE"), nullable=False, index=True
    )
    order_id: Mapped[int] = mapped_column(
        ForeignKey("orders.id", ondelete="RESTRICT"), nullable=False, index=True
    )

    upstream_disk_id: Mapped[int | None] = mapped_column(Integer, nullable=True, index=True)
    upstream_task_id: Mapped[int | None] = mapped_column(Integer, nullable=True, index=True)

    kind: Mapped[str] = mapped_column(String(24), default="create_disk", nullable=False)
    size_gb: Mapped[int] = mapped_column(Integer, nullable=False)
    source_size_gb: Mapped[int | None] = mapped_column(Integer, nullable=True)
    target_size_gb: Mapped[int | None] = mapped_column(Integer, nullable=True)
    delta_size_gb: Mapped[int | None] = mapped_column(Integer, nullable=True)
    store_id: Mapped[int] = mapped_column(Integer, nullable=False)
    driver: Mapped[str | None] = mapped_column(String(16), nullable=True)
    cache: Mapped[str | None] = mapped_column(String(32), nullable=True)
    io: Mapped[str | None] = mapped_column(String(16), nullable=True)
    iops_min: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    iops_max: Mapped[int] = mapped_column(Integer, default=0, nullable=False)

    cycle: Mapped[str] = mapped_column(String(16), nullable=False)
    current_charge_amount: Mapped[int] = mapped_column(Integer, nullable=False, comment="本次扣费，单位分")
    recurring_amount: Mapped[int] = mapped_column(Integer, nullable=False, comment="后续每周期费用，单位分")
    charged_until: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)

    status: Mapped[InstanceDiskAddonStatus] = mapped_column(
        SAEnum(InstanceDiskAddonStatus, values_callable=lambda e: [m.value for m in e]),
        default=InstanceDiskAddonStatus.PENDING,
        nullable=False,
        index=True,
    )

    payload_snapshot: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    remark: Mapped[str | None] = mapped_column(Text, nullable=True)
    activated_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    refunded_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
