"""Graph service handles graph management operations."""

from __future__ import annotations

from typing import TYPE_CHECKING, List

import grpc

if TYPE_CHECKING:
    from ..types import GraphInfo, GraphType
    from .service_context import ServiceContext


class GraphService:
    """Graph service for managing graphs."""

    def __init__(self, ctx: ServiceContext):
        self.ctx = ctx
        self._stub = None

    def _get_stub(self):
        if self._stub is None:
            from ..proto import gqldb_pb2_grpc
            channel = self.ctx.get_channel()
            self._stub = gqldb_pb2_grpc.GraphServiceStub(channel)
        return self._stub

    def create_graph(self, name: str, graph_type: GraphType, description: str) -> None:
        from ..errors import GqldbError
        from ..proto import gqldb_pb2

        try:
            request = gqldb_pb2.CreateGraphRequest(
                name=name,
                graph_type=graph_type.value,
                description=description
            )
            metadata = self.ctx.get_session_metadata()
            response = self._get_stub().CreateGraph(
                request, metadata=metadata, timeout=self.ctx.config.timeout
            )
            if not response.success:
                raise GqldbError(response.message)
        except grpc.RpcError as e:
            raise GqldbError(f"Create graph failed: {e.details()}") from e

    def drop_graph(self, name: str, if_exists: bool) -> None:
        from ..errors import GqldbError
        from ..proto import gqldb_pb2

        try:
            request = gqldb_pb2.DropGraphRequest(name=name, if_exists=if_exists)
            metadata = self.ctx.get_session_metadata()
            response = self._get_stub().DropGraph(
                request, metadata=metadata, timeout=self.ctx.config.timeout
            )
            if not response.success:
                raise GqldbError(response.message)
        except grpc.RpcError as e:
            raise GqldbError(f"Drop graph failed: {e.details()}") from e

    def use_graph(self, name: str) -> None:
        from ..errors import GqldbError
        from ..proto import gqldb_pb2

        session = self.ctx.sessions.get_session()
        try:
            request = gqldb_pb2.UseGraphRequest(
                name=name, session_id=session.id if session else 0
            )
            metadata = self.ctx.get_session_metadata()
            response = self._get_stub().UseGraph(
                request, metadata=metadata, timeout=self.ctx.config.timeout
            )
            if not response.success:
                raise GqldbError(response.message)
            self.ctx.sessions.set_default_graph(name)
        except grpc.RpcError as e:
            raise GqldbError(f"Use graph failed: {e.details()}") from e

    def list_graphs(self) -> List[GraphInfo]:
        from ..errors import GqldbError
        from ..proto import gqldb_pb2
        from .converters import convert_graph_info

        try:
            request = gqldb_pb2.ListGraphsRequest()
            metadata = self.ctx.get_session_metadata()
            response = self._get_stub().ListGraphs(
                request, metadata=metadata, timeout=self.ctx.config.timeout
            )
            return [convert_graph_info(g) for g in response.graphs]
        except grpc.RpcError as e:
            raise GqldbError(f"List graphs failed: {e.details()}") from e

    def get_graph_info(self, name: str) -> GraphInfo:
        from ..errors import GqldbError, GraphNotFoundError
        from ..proto import gqldb_pb2
        from .converters import convert_graph_info

        try:
            request = gqldb_pb2.GetGraphInfoRequest(name=name)
            metadata = self.ctx.get_session_metadata()
            response = self._get_stub().GetGraphInfo(
                request, metadata=metadata, timeout=self.ctx.config.timeout
            )
            if not response.info or not response.info.name:
                raise GraphNotFoundError(name)
            return convert_graph_info(response.info)
        except grpc.RpcError as e:
            if e.code() == grpc.StatusCode.NOT_FOUND:
                raise GraphNotFoundError(name) from e
            raise GqldbError(f"Get graph info failed: {e.details()}") from e
