# from flask import Flask, request, jsonify
# from flask_cors import CORS
# import cv2
# import numpy as np
# import base64

# app = Flask(__name__)
# CORS(app, origins=["http://localhost:3000"])  # Allow requests from http://localhost:3000
# # CORS(app)

# def decode_base64_image(base64_str):
#     header, encoded = base64_str.split(',', 1)
#     decoded_data = base64.b64decode(encoded)
#     np_data = np.frombuffer(decoded_data, np.uint8)
#     img = cv2.imdecode(np_data, cv2.IMREAD_COLOR)
#     return img

# @app.route('/match-templates', methods=['POST'])
# def match_templates():
#     data = request.json
#     master_image_base64 = data['master_image']
#     sub_images_base64 = data['sub_images']

#     master_image = decode_base64_image(master_image_base64)
#     master_h, master_w, _ = master_image.shape
#     areas = []

#     for sub_image_base64 in sub_images_base64:
#         sub_image = decode_base64_image(sub_image_base64)
#         h, w, _ = sub_image.shape

#         print(f"Matching template of size {w}x{h} in master image of size {master_w}x{master_h}")

#         # Perform template matching
#         result = cv2.matchTemplate(master_image, sub_image, cv2.TM_CCOEFF_NORMED)
#         min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)

#         print(f"Match result - Min Value: {min_val}, Max Value: {max_val}")
#         print(f"Min Location: {min_loc}, Max Location: {max_loc}")

#         # Define a lower threshold for the match quality
#         threshold = 0.5
#         if max_val >= threshold:
#             top_left = max_loc
#             bottom_right = (top_left[0] + w, top_left[1] + h)

#             # Convert coordinates to percentages
#             polygon = [
#                 (top_left[0] / master_w * 100, top_left[1] / master_h * 100),
#                 (bottom_right[0] / master_w * 100, top_left[1] / master_h * 100),
#                 (bottom_right[0] / master_w * 100, bottom_right[1] / master_h * 100),
#                 (top_left[0] / master_w * 100, bottom_right[1] / master_h * 100)
#             ]

#             areas.append({
#                 'sub_image': sub_image_base64,
#                 'polygons': [polygon]
#             })
#         else:
#             print(f"No match found with sufficient confidence for sub-image {sub_image_base64[:30]}...")

#     return jsonify({'areas': areas})

# if __name__ == '__main__':
#     app.run(debug=True)

# from flask import Flask, request, jsonify
# from flask_cors import CORS
# import cv2
# import numpy as np
# import base64

# app = Flask(__name__)
# # CORS(app)
# CORS(app, origins=["http://localhost:3000"])  # Allow requests from http://localhost:3000

# def decode_base64_image(base64_str):
#     try:
#         header, encoded = base64_str.split(',', 1)
#         decoded_data = base64.b64decode(encoded)
#         np_data = np.frombuffer(decoded_data, np.uint8)
#         img = cv2.imdecode(np_data, cv2.IMREAD_COLOR)
#         return img
#     except Exception as e:
#         print(f"Error decoding base64 image: {e}")
#         return None

# @app.route('/match-templates', methods=['POST'])
# def match_templates():
#     try:
#         data = request.json
#         master_image_base64 = data['master_image']
#         sub_images_base64 = data['sub_images']

#         master_image = decode_base64_image(master_image_base64)
#         if master_image is None:
#             return jsonify({'error': 'Invalid master image data'}), 400

#         master_h, master_w, _ = master_image.shape
#         areas = []

#         for sub_image_base64 in sub_images_base64:
#             sub_image = decode_base64_image(sub_image_base64)
#             if sub_image is None:
#                 continue

#             h, w, _ = sub_image.shape

#             # Perform template matching
#             result = cv2.matchTemplate(master_image, sub_image, cv2.TM_CCOEFF_NORMED)
#             min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)

#             # Define a lower threshold for the match quality
#             threshold = 0.5
#             if max_val >= threshold:
#                 top_left = max_loc
#                 bottom_right = (top_left[0] + w, top_left[1] + h)

#                 # Convert coordinates to percentages
#                 polygon = [
#                     (top_left[0] / master_w * 100, top_left[1] / master_h * 100),
#                     (bottom_right[0] / master_w * 100, top_left[1] / master_h * 100),
#                     (bottom_right[0] / master_w * 100, bottom_right[1] / master_h * 100),
#                     (top_left[0] / master_w * 100, bottom_right[1] / master_h * 100)
#                 ]

#                 areas.append({
#                     'sub_image': sub_image_base64,
#                     'polygons': [polygon]
#                 })

#         return jsonify({'areas': areas})

#     except Exception as e:
#         print(f"Error in /match-templates endpoint: {e}")
#         return jsonify({'error': 'Internal server error'}), 500

# if __name__ == '__main__':
#     app.run(debug=True)


# from flask import Flask, request, jsonify
# from flask_cors import CORS
# import cv2
# import numpy as np
# import base64
# import os

# app = Flask(__name__)
# CORS(app, origins=["http://localhost:3000"])  # Allow requests from http://localhost:3000

# def decode_base64_image(base64_str):
#     try:
#         header, encoded = base64_str.split(',', 1)
#         decoded_data = base64.b64decode(encoded)
#         np_data = np.frombuffer(decoded_data, np.uint8)
#         img = cv2.imdecode(np_data, cv2.IMREAD_COLOR)
#         if img is None:
#             raise ValueError("Decoded image is None")
#         return img
#     except Exception as e:
#         print(f"Error decoding base64 image: {e}")
#         return None

# def draw_rectangle(image, top_left, bottom_right, index):
#     cv2.rectangle(image, top_left, bottom_right, (0, 255, 0), 2)
#     cv2.putText(image, f'{index}', (top_left[0], top_left[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
#     return image

# @app.route('/match-templates', methods=['POST'])
# def match_templates():
#     try:
#         data = request.json
#         if 'master_image' not in data or 'sub_images' not in data:
#             return jsonify({'error': 'Invalid input data'}), 400

#         master_image_base64 = data['master_image']
#         sub_images_base64 = data['sub_images']

#         master_image = decode_base64_image(master_image_base64)
#         if master_image is None:
#             return jsonify({'error': 'Invalid master image data'}), 400

#         master_h, master_w, _ = master_image.shape
#         areas = []

#         for index, sub_image_base64 in enumerate(sub_images_base64):
#             sub_image = decode_base64_image(sub_image_base64)
#             if sub_image is None:
#                 print(f"Skipping invalid sub image data at index {index}")
#                 continue

#             h, w, _ = sub_image.shape
#             print(f"Matching template of size {w}x{h} in master image of size {master_w}x{master_h} (sub-image index: {index})")

#             # Perform template matching
#             result = cv2.matchTemplate(master_image, sub_image, cv2.TM_CCOEFF_NORMED)
#             min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)

#             print(f"Match result for sub-image index {index} - Min Value: {min_val}, Max Value: {max_val}")
#             print(f"Min Location: {min_loc}, Max Location: {max_loc}")

#             # Define a lower threshold for the match quality
#             threshold = 0.4  # Lower the threshold to capture more matches
#             if max_val >= threshold:
#                 top_left = max_loc
#                 bottom_right = (top_left[0] + w, top_left[1] + h)

#                 # Draw rectangle on master image for visualization
#                 master_image = draw_rectangle(master_image, top_left, bottom_right, index)

#                 # Convert coordinates to percentages
#                 polygon = [
#                     (top_left[0] / master_w * 100, top_left[1] / master_h * 100),
#                     (bottom_right[0] / master_w * 100, top_left[1] / master_h * 100),
#                     (bottom_right[0] / master_w * 100, bottom_right[1] / master_h * 100),
#                     (top_left[0] / master_w * 100, bottom_right[1] / master_h * 100)
#                 ]

#                 areas.append({
#                     'sub_image': sub_image_base64,
#                     'polygons': [polygon]
#                 })
#             else:
#                 print(f"No match found with sufficient confidence for sub-image index {index} {sub_image_base64[:30]}...")

#         # Save the master image with rectangles for manual inspection
#         cv2.imwrite('master_image_with_matches.png', master_image)

#         print(f"Total matched areas: {len(areas)}")
#         return jsonify({'areas': areas})

#     except Exception as e:
#         print(f"Error in /match-templates endpoint: {e}")
#         return jsonify({'error': 'Internal server error'}), 500

# if __name__ == '__main__':
#     # Ensure the output directory exists
#     if not os.path.exists('output'):
#         os.makedirs('output')
#     app.run(debug=True)


# from flask import Flask, request, jsonify
# from flask_cors import CORS
# import cv2
# import numpy as np
# import base64
# import os
# import concurrent.futures

# app = Flask(__name__)
# CORS(app, origins=["http://localhost:3000"])  # Allow requests from http://localhost:3000

# def decode_base64_image(base64_str):
#     try:
#         header, encoded = base64_str.split(',', 1)
#         decoded_data = base64.b64decode(encoded)
#         np_data = np.frombuffer(decoded_data, np.uint8)
#         img = cv2.imdecode(np_data, cv2.IMREAD_COLOR)
#         if img is None:
#             raise ValueError("Decoded image is None")
#         return img
#     except Exception as e:
#         print(f"Error decoding base64 image: {e}")
#         return None

# def draw_rectangle(image, top_left, bottom_right, index):
#     cv2.rectangle(image, top_left, bottom_right, (0, 255, 0), 2)
#     cv2.putText(image, f'{index}', (top_left[0], top_left[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
#     return image

# def match_template(master_image, master_w, master_h, sub_image_base64, index, threshold=0.4):
#     sub_image = decode_base64_image(sub_image_base64)
#     if sub_image is None:
#         print(f"Skipping invalid sub image data at index {index}")
#         return None

#     h, w, _ = sub_image.shape
#     print(f"Matching template of size {w}x{h} in master image of size {master_w}x{master_h} (sub-image index: {index})")

#     # Perform template matching
#     result = cv2.matchTemplate(master_image, sub_image, cv2.TM_CCOEFF_NORMED)
#     min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)

#     print(f"Match result for sub-image index {index} - Min Value: {min_val}, Max Value: {max_val}")
#     print(f"Min Location: {min_loc}, Max Location: {max_loc}")

#     if max_val >= threshold:
#         top_left = max_loc
#         bottom_right = (top_left[0] + w, top_left[1] + h)

#         # Convert coordinates to percentages
#         polygon = [
#             (top_left[0] / master_w * 100, top_left[1] / master_h * 100),
#             (bottom_right[0] / master_w * 100, top_left[1] / master_h * 100),
#             (bottom_right[0] / master_w * 100, bottom_right[1] / master_h * 100),
#             (top_left[0] / master_w * 100, bottom_right[1] / master_h * 100)
#         ]

#         return {
#             'sub_image': sub_image_base64,
#             'polygons': [polygon]
#         }
#     else:
#         print(f"No match found with sufficient confidence for sub-image index {index} {sub_image_base64[:30]}...")
#         return None

# @app.route('/match-templates', methods=['POST'])
# def match_templates():
#     try:
#         data = request.json
#         if 'master_image' not in data or 'sub_images' not in data:
#             return jsonify({'error': 'Invalid input data'}), 400

#         master_image_base64 = data['master_image']
#         sub_images_base64 = data['sub_images']

#         master_image = decode_base64_image(master_image_base64)
#         if master_image is None:
#             return jsonify({'error': 'Invalid master image data'}), 400

#         master_h, master_w, _ = master_image.shape
#         areas = []

#         # Use ThreadPoolExecutor for parallel processing
#         with concurrent.futures.ThreadPoolExecutor() as executor:
#             future_to_index = {
#                 executor.submit(match_template, master_image, master_w, master_h, sub_image_base64, index): index
#                 for index, sub_image_base64 in enumerate(sub_images_base64)
#             }
#             for future in concurrent.futures.as_completed(future_to_index):
#                 index = future_to_index[future]
#                 try:
#                     result = future.result()
#                     if result is not None:
#                         areas.append(result)
#                 except Exception as e:
#                     print(f"Error processing sub-image index {index}: {e}")

#         # Save the master image with rectangles for manual inspection
#         for area in areas:
#             for polygon in area['polygons']:
#                 top_left = (int(polygon[0][0] * master_w / 100), int(polygon[0][1] * master_h / 100))
#                 bottom_right = (int(polygon[2][0] * master_w / 100), int(polygon[2][1] * master_h / 100))
#                 draw_rectangle(master_image, top_left, bottom_right, 0)  # Index is not needed here

#         cv2.imwrite('output/master_image_with_matches.png', master_image)

#         print(f"Total matched areas: {len(areas)}")
#         return jsonify({'areas': areas})

#     except Exception as e:
#         print(f"Error in /match-templates endpoint: {e}")
#         return jsonify({'error': 'Internal server error'}), 500

# if __name__ == '__main__':
#     # Ensure the output directory exists
#     if not os.path.exists('output'):
#         os.makedirs('output')
#     app.run(debug=True)

import cv2
import numpy as np
import base64
import os
import concurrent.futures
from flask import Flask, request, jsonify
from flask_cors import CORS

print("Starting the Flask app...")  # Debugging statement

app = Flask(__name__)
CORS(app, origins=["http://localhost:3000"])

def decode_base64_image(base64_str):
    try:
        if ',' in base64_str:
            header, encoded = base64_str.split(',', 1)
            print(f"Header: {header}")  # Debugging
        else:
            encoded = base64_str
            print("No header found in the base64 string")  # Debugging
        decoded_data = base64.b64decode(encoded)
        np_data = np.frombuffer(decoded_data, np.uint8)
        img = cv2.imdecode(np_data, cv2.IMREAD_COLOR)
        if img is None:
            raise ValueError("Decoded image is None")
        return img
    except Exception as e:
        print(f"Error decoding base64 image: {e}")
        return None

def draw_rectangle(image, top_left, bottom_right, index):
    cv2.rectangle(image, top_left, bottom_right, (0, 255, 0), 2)
    cv2.putText(image, f'{index}', (top_left[0], top_left[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
    return image

def match_template(master_image, master_w, master_h, sub_image_base64, index, threshold=0.4):
    sub_image = decode_base64_image(sub_image_base64)
    if sub_image is None:
        print(f"Skipping invalid sub image data at index {index}")
        return None

    h, w, _ = sub_image.shape
    print(f"Matching template of size {w}x{h} in master image of size {master_w}x{master_h} (sub-image index: {index})")

    # Perform template matching
    result = cv2.matchTemplate(master_image, sub_image, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)

    print(f"Match result for sub-image index {index} - Min Value: {min_val}, Max Value: {max_val}")
    print(f"Min Location: {min_loc}, Max Location: {max_loc}")

    if max_val >= threshold:
        top_left = max_loc
        bottom_right = (top_left[0] + w, top_left[1] + h)

        # Convert coordinates to percentages
        polygon = [
            (top_left[0] / master_w * 100, top_left[1] / master_h * 100),
            (bottom_right[0] / master_w * 100, top_left[1] / master_h * 100),
            (bottom_right[0] / master_w * 100, bottom_right[1] / master_h * 100),
            (top_left[0] / master_w * 100, bottom_right[1] / master_h * 100)
        ]

        return {
            'sub_image': sub_image_base64,
            'polygons': [polygon]
        }
    else:
        print(f"No match found with sufficient confidence for sub-image index {index} {sub_image_base64[:30]}...")
        return None

@app.route('/match-templates', methods=['POST'])
def match_templates():
    print("Received a request on /match-templates")  # Debugging statement
    try:
        data = request.json
        if 'master_image' not in data or 'sub_images' not in data:
            return jsonify({'error': 'Invalid input data'}), 400

        master_image_base64 = data['master_image']
        sub_images_base64 = data['sub_images']

        print(f"Master image base64: {master_image_base64[:30]}...")  # Debugging

        master_image = decode_base64_image(master_image_base64)
        if master_image is None:
            print("Failed to decode master image")
            return jsonify({'error': 'Invalid master image data'}), 400

        master_h, master_w, _ = master_image.shape
        areas = []

        # Use ThreadPoolExecutor for parallel processing
        with concurrent.futures.ThreadPoolExecutor() as executor:
            future_to_index = {
                executor.submit(match_template, master_image, master_w, master_h, sub_image_base64, index): index
                for index, sub_image_base64 in enumerate(sub_images_base64)
            }
            for future in concurrent.futures.as_completed(future_to_index):
                index = future_to_index[future]
                try:
                    result = future.result()
                    if result is not None:
                        areas.append(result)
                except Exception as e:
                    print(f"Error processing sub-image index {index}: {e}")

        # Save the master image with rectangles for manual inspection
        for area in areas:
            for polygon in area['polygons']:
                top_left = (int(polygon[0][0] * master_w / 100), int(polygon[0][1] * master_h / 100))
                bottom_right = (int(polygon[2][0] * master_w / 100), int(polygon[2][1] * master_h / 100))
                draw_rectangle(master_image, top_left, bottom_right, 0)  # Index is not needed here

        cv2.imwrite('output/master_image_with_matches.png', master_image)

        print(f"Total matched areas: {len(areas)}")
        return jsonify({'areas': areas})

    except Exception as e:
        print(f"Error in /match-templates endpoint: {e}")
        return jsonify({'error': 'Internal server error'}), 500

if __name__ == '__main__':
    if not os.path.exists('output'):
        os.makedirs('output')
    print("Running the Flask app...")  # Debugging statement
    app.run(debug=True)
