"""GraphQL scalar mapping utilities for FraiseQL.

This module defines a mapping between common Python types (e.g., `uuid.UUID`, `datetime.datetime`)
and their corresponding GraphQL scalar types. It supports both standard GraphQL scalars
(e.g., `GraphQLString`, `GraphQLInt`, `GraphQLID`) and custom FraiseQL scalars with serialization logic.

The core function `convert_scalar_to_graphql()` is used to translate a Python type annotation
into its GraphQL scalar equivalent during schema generation.

Raises:
    TypeError: If the provided Python type has no corresponding GraphQL scalar.
"""

import datetime
import ipaddress
import uuid

from graphql import (
    GraphQLBoolean,
    GraphQLFloat,
    GraphQLID,
    GraphQLInt,
    GraphQLScalarType,
    GraphQLString,
)

from .date import DateScalar
from .daterange import DateRangeScalar
from .datetime import DateTimeScalar
from .ip_address import IpAddressScalar, SubnetMaskScalar
from .json import JSONField, JSONScalar
from .ltree import LTreeScalar
from .uuid import UUIDField


def convert_scalar_to_graphql(typ: type) -> GraphQLScalarType:
    """Convert a Python type to a corresponding GraphQL scalar type."""
    scalar_map: dict[type, GraphQLScalarType] = {
        str: GraphQLString,
        int: GraphQLInt,
        float: GraphQLFloat,
        bool: GraphQLBoolean,
        JSONField: JSONScalar,
        dict: JSONScalar,
        uuid.UUID: GraphQLID,
        UUIDField: GraphQLID,
        datetime.date: GraphQLScalarType(name="Date", serialize=DateScalar.serialize),
        datetime.datetime: GraphQLScalarType(name="DateTime", serialize=DateTimeScalar.serialize),
        datetime.time: GraphQLString,
        ipaddress.IPv4Address: GraphQLScalarType(
            name="IpAddress",
            serialize=IpAddressScalar.serialize,
        ),
        ipaddress.IPv4Network: GraphQLScalarType(
            name="SubnetMask",
            serialize=SubnetMaskScalar.serialize,
        ),
        tuple: GraphQLScalarType(name="DateRange", serialize=DateRangeScalar.serialize),
        list: GraphQLScalarType(name="LTree", serialize=LTreeScalar.serialize),
    }

    if typ in scalar_map:
        return scalar_map[typ]

    msg = f"Unsupported scalar type: {typ}"
    raise TypeError(msg)
