from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime
from enum import StrEnum
from typing import Any


class DataSource(StrEnum):
    TUSHARE = "tushare"
    IFIND = "ifind"
    EASTMONEY = "eastmoney"
    TENCENT = "tencent"
    LOCAL = "local"


class DataUsage(StrEnum):
    DISPLAY = "display"
    CALCULATION = "calculation"


class SnapshotState(StrEnum):
    REALTIME = "realtime"
    FINAL = "final"
    ARCHIVE = "archive"


@dataclass(frozen=True, slots=True)
class ObservationMetadata:
    source: DataSource
    observed_at: datetime
    unit: str
    adjustment: str
    freshness_seconds: int
    coverage: float
    state: SnapshotState
    usage: DataUsage

    def __post_init__(self) -> None:
        if not 0 <= self.coverage <= 1:
            raise ValueError("coverage must be between zero and one")
        if self.freshness_seconds < 0:
            raise ValueError("freshness_seconds cannot be negative")


@dataclass(frozen=True, slots=True)
class ProviderResult:
    rows: tuple[dict[str, Any], ...]
    metadata: ObservationMetadata


@dataclass(frozen=True, slots=True)
class TradeContext:
    requested_date: str
    actual_date: str | None
    previous_date: str | None
    observed_at: datetime | None
    state: SnapshotState | None
    carried_forward: bool
    message: str


@dataclass(frozen=True, slots=True)
class MarketEntity:
    entity_type: str
    identifier: str
    code: str
    name: str
    sector: str | None = None


@dataclass(frozen=True, slots=True)
class ChartPoint:
    time: str
    open: float
    high: float
    low: float
    close: float
    volume: float
    amount: float
    average: float | None = None


@dataclass(frozen=True, slots=True)
class ChartSeries:
    entity: MarketEntity
    interval: str
    trade_date: str
    previous_close: float | None
    points: tuple[ChartPoint, ...]
    metadata: ObservationMetadata
