from __future__ import annotations

from dataclasses import dataclass
from typing import Any


def normalize_flow_uri(flow_uri: str) -> str:
    value = str(flow_uri or "").strip()
    if not value:
        raise ValueError("flow_uri must be a non-empty string.")
    if not value.startswith("flow://"):
        raise ValueError("flow_uri must use flow:// scheme.")
    return value


def normalize_flow_program_version(version: str) -> str:
    value = str(version or "").strip()
    if not value:
        raise ValueError("version must be a non-empty string.")
    return value


@dataclass(frozen=True)
class FlowProgramRef:
    flow_uri: str
    version: str

    def __post_init__(self) -> None:
        object.__setattr__(self, "flow_uri", normalize_flow_uri(self.flow_uri))
        object.__setattr__(
            self,
            "version",
            normalize_flow_program_version(self.version),
        )

    def flow_id(self) -> str:
        return f"{self.flow_uri}@{self.version}"


@dataclass(frozen=True)
class ResolvedFlowProgram:
    payload: Any
    flow_uri: str
    version: str
    program_id: str | None = None
    program_hash: str | None = None

    def __post_init__(self) -> None:
        object.__setattr__(self, "flow_uri", normalize_flow_uri(self.flow_uri))
        object.__setattr__(
            self,
            "version",
            normalize_flow_program_version(self.version),
        )
        if self.program_id is not None and not str(self.program_id).strip():
            object.__setattr__(self, "program_id", None)
        if self.program_hash is not None and not str(self.program_hash).strip():
            object.__setattr__(self, "program_hash", None)

    def flow_id(self) -> str:
        return f"{self.flow_uri}@{self.version}"

    def lineage_entry(self) -> dict[str, str]:
        entry: dict[str, str] = {
            "flow_uri": self.flow_uri,
            "version": self.version,
        }
        if self.program_id is not None:
            entry["program_id"] = self.program_id
        if self.program_hash is not None:
            entry["program_hash"] = self.program_hash
        return entry


__all__ = [
    "FlowProgramRef",
    "ResolvedFlowProgram",
    "normalize_flow_uri",
    "normalize_flow_program_version",
]
