from shapely.geometry import LineString, Point, MultiLineString
from shapely.ops import polygonize, unary_union
from shapely.validation import explain_validity

def extract_polygon_and_holes(lines, points_dict):
    """
    lines: list of [[[x1, y1], [x2, y2]], ...]
    points_dict: dict like {"a": [x, y], "b": [x, y], ...}

    returns:
      polygon_lines = {"a": [[[x,y],[x,y]], ...], ...}
      hole_lines = {"a": [[[x,y],[x,y]], ...] or []}
    """

    # print("\n\nlines", lines, "\n\n")
    # print("\n\npoints_dict", points_dict, "\n\n")

    # Step 1: Create LineStrings
    mls = MultiLineString([ (tuple(p1), tuple(p2)) for p1, p2 in lines ])
    unioned = unary_union(mls)
    # Step 2: Polygonize to form closed polygons
    polygons = list(polygonize(unioned))

    print(len(polygons))

    # for i in polygons:
    #     print(i)

    polygon_lines = {}
    hole_lines = {}

    # Step 3: For each point, find containing polygon
    for label, coords in points_dict.items():

        
        pt = Point(coords['X'], coords['Y'])
        found_poly = None

        # print(pt)

        for poly in polygons:
            if poly.contains(pt):
                found_poly = poly
                break

        if found_poly:
            # Exterior lines
            exterior_coords = list(found_poly.exterior.coords)
            polygon_lines[label] = [
                [[exterior_coords[i][0], exterior_coords[i][1]],
                 [exterior_coords[i+1][0], exterior_coords[i+1][1]]]
                for i in range(len(exterior_coords)-1)
            ]

            # Interior (hole) lines
            holes = []
            for interior in found_poly.interiors:
                hole_coords = list(interior.coords)
                holes.extend([
                    [[hole_coords[i][0], hole_coords[i][1]],
                     [hole_coords[i+1][0], hole_coords[i+1][1]]]
                    for i in range(len(hole_coords)-1)
                ])
            hole_lines[label] = holes
        else:
            # No polygon found containing this point
            polygon_lines[label] = []
            hole_lines[label] = []


    # make subdiv 3D
    subdiv = {k: v for k, v in polygon_lines.items()}  # no wrapping
    inner_subdiv = {k: [v] if v else [] for k, v in hole_lines.items()}  # wrapping 4D

    return subdiv, inner_subdiv
