# Problem Description:
The task is to implement a function `solution` that determines whether a given rectangle is valid based on its corner coordinates and a set of points (dots) on a grid. A rectangle is considered valid if it does not contain any of the given points either inside or on its boundary.

# Visual Facts:
1. **Grid and Points**:
   - The grid is marked with integer coordinates on both axes.
   - Red dots represent points on the grid.
2. **Rectangles**:
   - Rectangles are drawn using two different colors: orange and green.
   - The corners of each rectangle align with the grid lines.
3. **Rectangle Labels**:
   - Orange Rectangles: Labeled "Invalid." Contain at least one red point inside them.
   - Green Rectangles: Labeled "Valid." Contain no red points inside them.
4. **Key Points on Labels**:
   - The text "Containing point" is used to indicate rectangles that have red points inside.
   - The text "No Point" is used to indicate rectangles without red points.

# Visual Patterns:
1. **Validity Rule**:
   - A rectangle is valid if and only if there are no red points (dots) either inside or on its boundary.
   - A rectangle becomes invalid if at least one red point lies either inside or on its boundary.
2. **Boundary Rules**:
   - Red dots on the boundary of the rectangle count towards the validity condition.
3. **Grid Alignment**:
   - Rectangles are axis-aligned, meaning their edges are parallel to the x-axis and y-axis.
   - The coordinates of the top_left and bottom_right corners are sufficient to define a rectangle.
4. **Input Constraints**:
   - The list of dots represents red points on the grid.
   - The top_left corner has a higher y-coordinate than the bottom_right corner, consistent with the standard Cartesian grid.

# Solution
import matplotlib.pyplot as plt
from typing import List, Tuple
import matplotlib.pyplot as plt

def solution(dots: List[Tuple[int, int]], top_left: Tuple[int, int], bottom_right: Tuple[int, int]) -> bool:
    """
    Determines whether a rectangle is valid given its corner coordinates and a set of dots.

    Parameters:
        dots: A list of coordinate pairs representing points in a grid.
        top_left: The coordinates of the rectangle's top-left corner.
        bottom_right: The coordinates of the rectangle's bottom-right corner 
                     (note: y-coordinate of top_left > y-coordinate of bottom_right).

    Returns:
        True if the rectangle is valid, False otherwise.
    """
    # Extract the rectangle boundaries
    x1, y1 = top_left
    x2, y2 = bottom_right
    # Check for dots inside the rectangle
    for x, y in dots:
        if x1 <= x <= x2 and y2 <= y <= y1:
            # visualize(dots, top_left, bottom_right, is_valid=False)
            return False
    # visualize(dots, top_left, bottom_right, is_valid=True)
    return True

# def visualize(dots: List[Tuple[int, int]], top_left: Tuple[int, int], bottom_right: Tuple[int, int], is_valid: bool):
#     """
#     Visualize the dots and rectangle.

#     Parameters:
#         dots: A list of tuples representing the coordinates of dots in the grid.
#         top_left: The coordinates of the top-left corner of the rectangle.
#         bottom_right: The coordinates of the bottom-right corner of the rectangle.
#         is_valid: Whether the rectangle is valid or not.
#     """
#     # Create a scatter plot of the dots
#     plt.figure(figsize=(8, 8))
#     x_coords, y_coords = zip(*dots) if dots else ([], [])
#     plt.scatter(x_coords, y_coords, c='blue', label='Dots', s=50, edgecolor='black')

#     # Draw the rectangle
#     x1, y1 = top_left
#     x2, y2 = bottom_right
#     rect_color = 'green' if is_valid else 'red'
#     plt.plot([x1, x2, x2, x1, x1], [y1, y1, y2, y2, y1], c=rect_color, label='Rectangle', linewidth=2)

#     # Add labels and legend
#     plt.title(f'Rectangle Validity: {"Valid" if is_valid else "Invalid"}', fontsize=16, color=rect_color)
#     plt.xlabel('X Coordinate')
#     plt.ylabel('Y Coordinate')
#     plt.legend()
#     plt.grid(True)
#     plt.gca().set_aspect('equal', adjustable='box')

#     # Show the plot
#     plt.show()

# Test Script
def test():
    test_cases = [
        ([(1, 1), (3, 3), (5, 5)], (2, 6), (6, 2), False),
        ([(1, 1), (2, 3), (4, 6)], (2, 6), (6, 2), False),
        ([(2, 0), (3, 0), (5, 6)], (1, 6), (6, 1), False),
        ([(1, 1), (3, 3), (5, 5)], (2, 4), (4, 2), False),
        ([], (2, 6), (6, 2), True),
        ([(1, 1), (7, 7), (9, 9)], (2, 9), (3, 6), True),
        ([(10, 10), (20, 20), (30, 30)], (13, 25), (15, 12), True),
        ([(10, 10), (20, 20), (15, 15)], (12, 18), (13, 7), True),
        ([(2, 2), (3, 3)], (1, 5), (5, 1), False),
        ([(2, 2), (4, 4)], (1, 3), (3, 1), False),
        ([(0, 0), (9, 9)], (0, 10), (10, 0), False),
    ]
    for dots, top_left, bottom_right, expected_output in test_cases:
        try:
            output = solution(dots, top_left, bottom_right)
        except Exception as e:
            error_message = (
                f"An exception occurred while running the test case:\n"
                f"`dots`: {dots}\n"
                f"`top_left`: {top_left}\n" 
                f"`bottom_right`: {bottom_right}\n\n"
                f"Exception: '{str(e)}'"
            )
            assert False, error_message

        if output != expected_output:
            error_message = (
                f"The following Test Case failed:\n"
                f"`dots`: {dots}\n"
                f"`top_left`: {top_left}\n"
                f"`bottom_right`: {bottom_right}\n\n"
                f"Actual Output: {output}\n"
                f"Expected Output: {expected_output}"
            )
            assert False, error_message

test()