from __future__ import annotations

from typing import Any

from zvondb.client import RegistryClient
from zvondb.models import ExperimentInfo, ProjectInfo


class Experiment:
    """Handle to an experiment within a project. Used to start jobs."""

    def __init__(
        self,
        client: RegistryClient,
        project: str,
        name: str,
        project_info: ProjectInfo | None = None,
    ):
        self._client = client
        self._project = project
        self._name = name
        self._project_info = project_info

    @property
    def name(self) -> str:
        return self._name

    def info(self) -> ExperimentInfo:
        data = self._client.get(
            f"/projects/{self._project}/experiments/{self._name}"
        )
        return ExperimentInfo(**data)

    def start_job(
        self,
        name: str,
        git_sha: str,
        metadata: dict[str, Any] | None = None,
        tracking_url: str | None = None,
        report: bool = True,
    ) -> "Job":
        from zvondb.job import Job, _validate_lengths

        _validate_lengths(name=name)
        if len(git_sha) > 40:
            raise ValueError(f"'git_sha' is {len(git_sha)} chars, max is 40")
        if not report:
            return Job(
                client=self._client,
                project=self._project,
                experiment=self._name,
                project_info=self._project_info,
                report=False,
            )

        data = self._client.post(
            f"/projects/{self._project}/jobs",
            json={
                "name": name,
                "experiment": self._name,
                "git_sha": git_sha,
                "metadata": metadata or {},
                "tracking_url": tracking_url,
            },
        )
        return Job(
            client=self._client,
            project=self._project,
            experiment=self._name,
            job_id=data["id"],
            project_info=self._project_info,
        )

    def register(
        self,
        name: str,
        type: str,
        storage_name: str | None = None,
        description: str = "",
        metadata: dict[str, Any] | None = None,
        tags: list[str] | None = None,
        path: str | None = None,
    ) -> str:
        """Register an external artifact without a manual job.

        Creates a short-lived 'register' job, creates the artifact, and
        completes the job automatically. Returns the artifact path.

        Either ``storage_name`` or ``path`` must be provided.
        """
        from zvondb.job import Job

        job_data = self._client.post(
            f"/projects/{self._project}/jobs",
            json={
                "name": "register",
                "experiment": self._name,
                "git_sha": "external",
                "metadata": {"registered": True},
            },
        )
        job = Job(
            client=self._client,
            project=self._project,
            experiment=self._name,
            job_id=job_data["id"],
            project_info=self._project_info,
        )
        try:
            artifact_path = job.create(
                name=name,
                type=type,
                storage_name=storage_name,
                description=description,
                metadata=metadata,
                tags=tags,
                path=path,
            )
            job.complete()
        except Exception:
            job.fail(reason="Registration failed")
            raise
        return artifact_path
