from __future__ import annotations

from abc import ABC, abstractmethod
from pathlib import Path
from typing import cast

from dataiku import Folder
from typing_extensions import TypedDict

from recipes.build_graph.assets import (
    BUILD_INFO_JSON_FILENAME,
    BUILT_GRAPHS_PREFIX,
    CONFIGURATION_JSON_FILENAME,
)
from solutions.graph.models import DbType, GraphMetadataSnapshot


class GraphBuildInfo(TypedDict):
    epoch_ms: int


class AbstractConnectionInfo(ABC):
    """Abstract base class for graph connection information."""

    @property
    @abstractmethod
    def type(self) -> DbType:
        """The type of the database (for example `kuzu` or `neo4j`)."""

    @property
    @abstractmethod
    def uid(self) -> str:
        """The unique identifier for this connection."""

    @property
    @abstractmethod
    def db_folder(self) -> Folder | None:
        """The DSS folder where the database or its metadata is stored."""

    @property
    def configuration_path(self) -> Path:
        return Path(BUILT_GRAPHS_PREFIX) / self.uid / CONFIGURATION_JSON_FILENAME

    @property
    def build_info_path(self) -> Path:
        return Path(BUILT_GRAPHS_PREFIX) / self.uid / BUILD_INFO_JSON_FILENAME

    def get_build_info(self) -> GraphBuildInfo | None:
        if self.db_folder:
            build_info = self.db_folder.read_json(self.build_info_path)
            if "epoch_ms" not in build_info:
                raise ValueError(f"Missing 'epoch_ms' in build info for snapshot {self.uid}")
            return cast(GraphBuildInfo, build_info)
        return None

    def get_configuration(self) -> GraphMetadataSnapshot | None:
        if self.db_folder:
            configuration = self.db_folder.read_json(self.configuration_path)
            return cast(GraphMetadataSnapshot, configuration)
        return None
