import cv2
import logging
import numpy as np
from pytiled_parser import parse_tileset, Tile
from pytiled_parser.common_types import OrderedPair
from pytiled_parser.tiled_object import TiledObject, Polygon
from pytiled_parser.layer import ObjectLayer
import xml.etree.ElementTree as ET

# Configure logging
logging.basicConfig(filename='process_map.log', level=logging.DEBUG,
                    format='%(asctime)s - %(levelname)s - %(message)s')

def save_tileset(tileset, tsx_path):
    # Parse the existing TSX file
    tree = ET.parse(tsx_path)
    root = tree.getroot()

    # Ensure tiles dictionary is initialized
    if tileset.tiles is None:
        tileset.tiles = {}

    # Iterate over tiles with colliders

   # logging.basicConfig(filename='process_map.log', level=logging.DEBUG,format=tile) 

    for tile_id, tile in tileset.tiles.items():
        if tile.objects:
            # Find or create the <tile> element
            tile_elem = root.find(f"./tile[@id='{tile_id}']")
            if tile_elem is None:
                tile_elem = ET.SubElement(root, 'tile', id=str(tile_id))
            else:
                # Remove existing objectgroup
                for og in tile_elem.findall('objectgroup'):
                    tile_elem.remove(og)

            # Create <objectgroup> element
            og_elem = ET.SubElement(tile_elem, 'objectgroup', draworder="index")
            for obj in tile.objects.tiled_objects:  # Updated attribute
                obj_attribs = {
                    'id': str(obj.id),
                    'x': str(obj.x),
                    'y': str(obj.y),
                }
                if obj.polygon:
                    # Handle polygon collider
                    object_elem = ET.SubElement(og_elem, 'object', obj_attribs)
                    points_str = ' '.join(['{0},{1}'.format(pt.x, pt.y) for pt in obj.polygon.points])
                    ET.SubElement(object_elem, 'polygon', points=points_str)
                else:
                    # Handle rectangle collider
                    obj_attribs.update({
                        'width': str(obj.width),
                        'height': str(obj.height),
                    })
                    ET.SubElement(og_elem, 'object', obj_attribs)

    # Write the updated TSX file
    tree.write(tsx_path, encoding='utf-8', xml_declaration=True)

def process_map(image_path, tsx_path, sensitivity=100):
    """
    Processes the tileset image, detects colliders for each tile,
    and updates the TSX file with collider data.
    """
    try:
        logging.info("Starting image processing...")

        # Parse the TSX file
        tileset = parse_tileset(tsx_path)
        if not tileset:
            logging.error(f"Tileset could not be parsed: {tsx_path}")
            return

        # Ensure tiles dictionary is initialized
        if tileset.tiles is None:
            tileset.tiles = {}

        # Load the tileset image
        tileset_image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
        if tileset_image is None:
            logging.error(f"Tileset image could not be loaded: {image_path}")
            return

        tile_width = tileset.tile_width
        tile_height = tileset.tile_height

        # Calculate the number of tiles in x and y directions
        tiles_x = tileset_image.shape[1] // tile_width
        tiles_y = tileset_image.shape[0] // tile_height

        for ty in range(tiles_y):
            for tx in range(tiles_x):
                # Extract the tile image
                tile_image = tileset_image[
                    ty * tile_height : (ty + 1) * tile_height,
                    tx * tile_width : (tx + 1) * tile_width
                ]

                # Process the tile image
                edges = cv2.Canny(tile_image, threshold1=sensitivity, threshold2=sensitivity * 2)

                # Find contours in the tile
                contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

                if contours:
                    # Compute the global tile ID
                    tile_id = ty * tiles_x + tx

                    # Get or create the tile in the tileset
                    tile = tileset.tiles.get(tile_id)
                    if not tile:
                        tile = Tile(id=tile_id)
                        tileset.tiles[tile_id] = tile

                    # Create an ObjectLayer for the tile if it doesn't exist
                    logging.info(tile)
                    if tile.objects is None:
                        tile.objects = ObjectLayer(
                            name="Colliders",
                            draw_order="index",
                            tiled_objects=[]  # Corrected parameter name
                        )

                    # Add collision objects to the tile's ObjectLayer
                    for cnt in contours:
                        # Calculate contour area and tile area
                        contour_area = cv2.contourArea(cnt)
                        tile_area = tile_width * tile_height
                        area_ratio = contour_area / tile_area

                        print(f"Tile objects: {tile.objects.tiled_objects}") #boş bir dizi dönüyor
                        print(f"x: {x}, y: {y}, w: {w}, h: {h}")


                        if area_ratio > 0.5:
                            # Create a polygon collider
                            # Adjust contour points to ensure they are within tile boundaries
                            points = cnt.reshape(-1, 2)

                            # Clamp points to tile boundaries
                            points[:, 0] = np.clip(points[:, 0], 0, tile_width)
                            points[:, 1] = np.clip(points[:, 1], 0, tile_height)

                            # Convert points to relative positions using OrderedPair
                            polygon_points = [OrderedPair(x=float(pt[0]), y=float(pt[1])) for pt in points]

                            # Create the TiledObject with a polygon
                            collider = TiledObject(
                                id=len(tile.objects.tiled_objects) + 1,
                                x=0,
                                y=0,
                                polygon=Polygon(points=polygon_points)
                            )
                        else:
                            # Create a rectangle collider
                            x, y, w, h = cv2.boundingRect(cnt)

                            # Ensure rectangle is within tile boundaries
                            x = max(0, min(x, tile_width))
                            y = max(0, min(y, tile_height))
                            w = min(w, tile_width - x)
                            h = min(h, tile_height - y)

                            collider = TiledObject(
                                id=len(tile.objects.tiled_objects) + 1,
                                x=float(x),
                                y=float(y),
                                width=float(w),
                                height=float(h)
                            )

                        tile.objects.tiled_objects.append(collider)  # Use 'tiled_objects'

        # Save the modified tileset
        save_tileset(tileset, tsx_path)

        logging.info("Collider settings successfully added.")

    except Exception as e:
        logging.error(f"An unexpected error occurred: {e}")

# User input for sensitivity value
image_path = "harita.png"  # Path to the tileset image
tsx_path = r"C:\Users\Casper\Downloads\project-bolt-sb1-rfjg3a (1)\project\project_map\tsx\fabrika.tsx"
sensitivity = int(input("Enter sensitivity value (e.g., 100): "))

# Process the map and add colliders to the TSX file
process_map(
    r"C:\Users\Casper\Downloads\project-bolt-sb1-rfjg3a (1)\project\project_map\fabrika (2).png",
    tsx_path,
    sensitivity
)


bu kodun amacı resimden ve tiled dosyasından yine hç bir collider bilgisi içermeyen bir tiled dosyasına yeni collider bilgilerini yazmak ve bunu yapay zeka ile görüntü işleyerek yapmak