from PIL import Image, ImageDraw,ImageFont
from paddleocr import PaddleOCR
import numpy as np

def add_text_to_box(image, location, text,color):
 
    draw = ImageDraw.Draw(image)

    x_min, y_min, x_max, y_max = location
    width = x_max-x_min
    height = y_max-y_min
    font_size = 2  
    font_path = "Arial.ttf"  
    font = ImageFont.truetype(font_path, font_size)

    while True:
        bbox = font.getbbox(text)
        text_width, text_height = bbox[2] - bbox[0], bbox[3] - bbox[1]
        if text_width >= width or text_height >= height:
            break
        font_size += 1
        font = ImageFont.truetype(font_path, font_size)

    font_size -= 1
    font = ImageFont.truetype(font_path, font_size)

    bbox = font.getbbox(text)
    text_width, text_height = bbox[2] - bbox[0], bbox[3] - bbox[1]

    ascent, descent = font.getmetrics()
    baseline_offset = (text_height - ascent)

    text_x = x_min + (width - text_width) // 2
    text_y = y_min + (height - text_height) // 2 -descent

    draw.text((text_x, text_y), text, font=font, fill=color)
    return image

def is_overlap(box1, box2):
    return not (box1[2] < box2[0] or box1[0] > box2[2] or box1[3] < box2[1] or box1[1] > box2[3])
def is_vertical_overlap(box1, box2):
        _, y_min, _,  y_max= box1
        _, y2_min, _, y2_max = box2
        return y_max> y2_min and y2_max> y_min

def merge_boxes(box1, box2):
    return [
        min(box1[0], box2[0]),
        min(box1[1], box2[1]),
        max(box1[2], box2[2]),
        max(box1[3], box2[3]),
    ]
def detect_text_save(image_path,output_path,min_width=0,min_height=0,output_path_id = None):
    image = Image.open(image_path).convert("RGBA")  

    image_id = image.copy()
    ocr = PaddleOCR(use_angle_cls=True, lang='en')  
    results= ocr.ocr(image_path, cls=True)
    output =[]
    id = 0
    draw = ImageDraw.Draw(image, "RGBA")
    draw_id = ImageDraw.Draw(image_id, "RGBA")

    if results[0] == None:
        image = image.convert("RGB")

        image.save(output_path)
        if output_path_id !=None:
            image_id.save(output_path_id)
        return []
    sorted_results =  sorted(
        [
            {
                "Location": [
                    int(min([point[0] for point in bbox])),
                    int(min([point[1] for point in bbox])),
                    int(max([point[0] for point in bbox])),
                    int(max([point[1] for point in bbox])),
                ],
                "text": text,
            }
            for bbox, (text, _) in results[0]
            if (int(max([point[0] for point in bbox])) - int(min([point[0] for point in bbox])) >= min_width) and
           (int(max([point[1] for point in bbox])) - int(min([point[1] for point in bbox])) >= min_height)

        ],
        key=lambda x: (x["Location"][1], x["Location"][0]) 
    )
    merged_boxes = []
    for result in sorted_results:
        current_box = result["Location"]
        text = result["text"]

        merged = False
        for item in merged_boxes:
            if is_overlap(current_box, item["Location"]):
                item["Location"] = merge_boxes(item["Location"], current_box)
                item["text"] += " " + text
                merged = True
                break
        if not merged:
            merged_boxes.append({
                "text": text,
                "Location": current_box
            })

    output = []
    draw = ImageDraw.Draw(image, "RGBA")
    outer_border_color = (0, 0, 0, 255)  
    fill_color = (255, 255, 255, 255)
    rows = []
    for element in sorted(merged_boxes, key=lambda b: b['Location'][1]):
        box = element['Location']
        added = False
        for row in rows:
            if is_vertical_overlap(row[-1]['Location'], box):  
                row.append(element)
                added = True
                break
        if not added:
            rows.append([element])  
    sorted_boxes = []
    for row in rows:
        sorted_boxes.extend(sorted(row, key=lambda b: b['Location'][0]))
    for idx, item in enumerate(sorted_boxes):
        x_min, y_min, x_max, y_max = item["Location"]
        draw.rectangle(((x_min-5, y_min-5), (x_max+5, y_max+5)), fill=fill_color)
        draw.rectangle(((x_min-5, y_min-5), (x_max+5, y_max+5)), outline=outer_border_color, width=10)
        draw_id.rectangle(((x_min-5, y_min-5), (x_max+5, y_max+5)), fill=fill_color)
        draw_id.rectangle(((x_min-5, y_min-5), (x_max+5, y_max+5)), outline=outer_border_color, width=10)

        output.append({
            "id": idx+1,
            "text": item["text"],
            "Location": item["Location"]
        })
        image_id = add_text_to_box(
            image_id,
            (x_min, y_min, x_max, y_max),
            str(idx + 1),"red"
        )

    image = image.convert("RGB")
    image.save(output_path)  
    if output_path_id !=None:
        image_id.save(output_path_id)
    return output


