from functools import lru_cache
from pathlib import Path
from typing import Any

from supabase import create_client

from harbor.models.metric.config import MetricConfig
from harbor.models.metric.type import MetricType
from harbor.models.registry import DatasetSpec, RegistryTaskId
from harbor.registry.client.base import BaseRegistryClient
from harbor.registry.client.harbor.config import (
    HARBOR_SUPABASE_PUBLISHABLE_KEY,
    HARBOR_SUPABASE_URL,
)


def _get_supabase_client():
    return create_client(
        HARBOR_SUPABASE_URL,
        HARBOR_SUPABASE_PUBLISHABLE_KEY,
    )


@lru_cache(maxsize=1)
def _fetch_all_datasets_from_supabase() -> list[dict[str, Any]]:
    supabase = _get_supabase_client()
    response = (
        supabase.table("dataset")
        .select("*, dataset_task(*), dataset_metric(*)")
        .execute()
    )
    return response.data or []


def _parse_dataset_data(data: dict[str, Any]) -> DatasetSpec:
    tasks = [
        RegistryTaskId(
            name=item["name"],
            git_url=item["git_url"],
            git_commit_id=item["git_commit_id"],
            path=Path(item["path"]),
        )
        for item in data.get("dataset_task", [])
    ]

    metrics = [
        MetricConfig(
            type=MetricType(item["metric_name"]),
            kwargs=item.get("kwargs") or {},
        )
        for item in data.get("dataset_metric", [])
    ]

    return DatasetSpec(
        name=data["name"],
        version=data["version"],
        description=data.get("description") or "",
        tasks=tasks,
        metrics=metrics,
    )


class HarborRegistryClient(BaseRegistryClient):
    def __init__(self, url: str | None = None, path: Path | None = None):
        super().__init__(url, path)

    def get_datasets(self) -> list[DatasetSpec]:
        datasets_data = _fetch_all_datasets_from_supabase()
        return [_parse_dataset_data(data) for data in datasets_data]

    def get_dataset_versions(self, name: str) -> list[str]:
        supabase = _get_supabase_client()
        response = (
            supabase.table("dataset").select("version").eq("name", name).execute()
        )
        if not response.data:
            raise ValueError(f"Dataset {name} not found")
        return [row["version"] for row in response.data]

    def _get_dataset_spec(self, name: str, version: str) -> DatasetSpec:
        supabase = _get_supabase_client()

        try:
            response = supabase.rpc(
                "get_dataset", {"p_name": name, "p_version": version}
            ).execute()
        except Exception:
            raise ValueError(f"Error getting dataset {name}@{version}")

        if not response.data:
            raise ValueError(f"Dataset {name}@{version} not found")

        data = response.data
        tasks = [
            RegistryTaskId(
                name=t["name"],
                git_url=t["git_url"],
                git_commit_id=t["git_commit_id"],
                path=Path(t["path"]),
            )
            for t in data.get("tasks", [])
        ]

        metrics = [
            MetricConfig(
                type=MetricType(m["name"]),
                kwargs=m.get("kwargs") or {},
            )
            for m in data.get("metrics", [])
        ]

        return DatasetSpec(
            name=data["name"],
            version=data["version"],
            description=data.get("description") or "",
            tasks=tasks,
            metrics=metrics,
        )
