from typing import List, Optional, Union

from galtea.domain.exceptions.entity_not_found_exception import EntityNotFoundException
from galtea.domain.models.product import Product
from galtea.infrastructure.clients.http_client import Client
from galtea.utils.sort_order import SortOrder, normalize_sort_order
from galtea.utils.string import build_query_params, is_valid_id
from galtea.utils.timestamp import normalize_timestamp


class ProductService:
    def __init__(self, client: Client):
        self.__client = client

    def get(self, product_id: str):
        """
        Retrieve a product by its ID.

        Args:
            product_id (str): ID of the product to retrieve.

        Returns:
            Product: The retrieved product object.
        """
        if not is_valid_id(product_id):
            raise ValueError("Product ID provided is not valid.")

        response = self.__client.get(f"products/{product_id}")
        return Product(**response.json())

    def get_by_name(self, name: str):
        """
        Retrieve a product by its name.

        Args:
            name (str): Name of the product to retrieve.

        Returns:
            Product: The retrieved product object.
        """
        query_params = build_query_params(names=[name])
        response = self.__client.get(f"products?{query_params}")
        products = [Product(**product) for product in response.json()]

        if not products:
            raise EntityNotFoundException(f"Product with name {name} does not exist.")

        return products[0]

    def delete(self, product_id: str):
        """
        Delete a product by its ID.

        Args:
            product_id (str): ID of the product to delete.

        Returns:
            None: None.
        """
        if not is_valid_id(product_id):
            raise ValueError("Product ID provided is not valid.")

        self.__client.delete(f"products/{product_id}")

    def list(
        self,
        from_created_at: Optional[Union[str, int]] = None,
        to_created_at: Optional[Union[str, int]] = None,
        sort_by_created_at: Optional[Union[str, SortOrder]] = None,
        offset: Optional[int] = None,
        limit: Optional[int] = None,
    ) -> List[Product]:
        """
        Get a list of products.

        Args:
            from_created_at (str | int, optional): Filter products created at or after this timestamp.
                Accepts ISO 8601 string (e.g., '2024-01-01T00:00:00Z') or Unix timestamp (seconds).
            to_created_at (str | int, optional): Filter products created at or before this timestamp.
                Accepts ISO 8601 string (e.g., '2024-12-31T23:59:59Z') or Unix timestamp (seconds).
            sort_by_created_at (str | SortOrder, optional): Sort by created at. Valid values are 'asc' and 'desc'.
            offset (int, optional): Offset for pagination.
            limit (int, optional): Limit for pagination.

        Returns:
            list[Product]: List of products.
        """
        sort_by_created_at = normalize_sort_order(sort_by_created_at) if sort_by_created_at is not None else None

        # Normalize date filter parameters
        from_created_at_normalized = normalize_timestamp(from_created_at)
        to_created_at_normalized = normalize_timestamp(to_created_at)

        query_params = build_query_params(
            fromCreatedAt=from_created_at_normalized,
            toCreatedAt=to_created_at_normalized,
            offset=offset,
            limit=limit,
            sort=["createdAt", sort_by_created_at] if sort_by_created_at else None,
        )
        response = self.__client.get(f"products?{query_params}")
        products = [Product(**product) for product in response.json()]
        return products
