# coding: utf-8
from supervisely.geometry.constants import EXTERIOR, INTERIOR, POINTS


def _is_2d_typed_coords_valid(coords, individual_coord_types):
    """
    Validate 2D coordinates.

    :param coords: List of 2D coordinates.
    :type coords: list
    :param individual_coord_types: Types of individual coordinates.
    :type individual_coord_types: tuple
    :returns: True if validation successful, False otherwise.
    :rtype: bool
    """
    return isinstance(coords, (list, tuple)) and all(
        len(point) == 2 and all(isinstance(coord, individual_coord_types) for coord in point)
        for point in coords
    )


def _is_2d_numeric_coords_valid(coords) -> bool:
    """
    :param coords: list or tuple of 2 numbers.
    :type coords: list or tuple
    :returns: True if validation successful, False otherwise.
    :rtype: bool
    """
    return _is_2d_typed_coords_valid(coords, (int, float))


def is_2d_int_coords_valid(coords) -> bool:
    """
    :param coords: list (or tuple) of 2 integers.
    :type coords: list or tuple
    :returns: True if validation successful, False otherwise.
    :rtype: bool
    """
    return _is_2d_typed_coords_valid(coords, (int,))


def validate_geometry_points_fields(json_obj: dict) -> None:
    """
    Validate json geometry points container structure, which presented as python dict.
    :param json_obj: example: { "points": { "exterior": [[1,2], [10, 20]], "interior": [[2,3]] } }
    :type json_obj: dict
    :returns: None
    :rtype: None
    """
    if POINTS not in json_obj:
        raise ValueError("Input data must contain {} field.".format(POINTS))

    points_obj = json_obj[POINTS]
    if not isinstance(points_obj, dict):
        raise TypeError('Input data field "{}" must be dict object.'.format(POINTS))

    if EXTERIOR not in points_obj or INTERIOR not in points_obj:
        raise ValueError(
            '"{}" field must contain {} and {} fields.'.format(POINTS, EXTERIOR, INTERIOR)
        )

    if not _is_2d_numeric_coords_valid(points_obj[EXTERIOR]):
        raise TypeError("{} field must be a list of 2 numbers lists.".format(EXTERIOR))

    interior = points_obj[INTERIOR]
    if not isinstance(interior, list) or not all(
        _is_2d_numeric_coords_valid(interior_component) for interior_component in interior
    ):
        raise TypeError("{} field must be a list of lists of 2 numbers lists.".format(INTERIOR))
