import pika
import base64
import json
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.responses import StreamingResponse, HTMLResponse
from io import BytesIO
from detectron2.utils.logger import setup_logger
import numpy as np
import cv2
import os
from detectron2 import model_zoo
from detectron2.engine import DefaultPredictor
from detectron2.config import get_cfg
from detectron2.utils.visualizer import Visualizer
from detectron2.data import MetadataCatalog

app = FastAPI()
setup_logger()

cfg = get_cfg()
cfg.MODEL.DEVICE = "cpu"
cfg.merge_from_file(model_zoo.get_config_file("COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml"))
cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.5
cfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url("COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml")
predictor = DefaultPredictor(cfg)

# Ensure the "save" folder exists
if not os.path.exists("save"):
    os.makedirs("save")


def read_base64(base64_str):
    try:
        # Add padding to the base64 string if it's missing
        padding = '=' * (4 - len(base64_str) % 4)
        base64_str += padding

        encoded_data = base64_str.split(b',')[1]
        data = base64.b64decode(encoded_data)
        nparr = np.frombuffer(data, np.uint8)
        return cv2.imdecode(nparr, cv2.IMREAD_UNCHANGED)
    except Exception as e:
        print(f"Error decoding base64: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Error decoding base64: {str(e)}")

def process(image, save_path):
    im = read_base64(image)
    outputs = predictor(im)
    v = Visualizer(im[:, :, ::-1], MetadataCatalog.get(cfg.DATASETS.TRAIN[0]), scale=1.2)
    out = v.draw_instance_predictions(outputs["instances"].to("cpu"))
    
    # Save the processed image in the "save" folder
    save_path = os.path.join("save", save_path)
    cv2.imwrite(save_path, out.get_image()[:, :, ::-1])
    
    return save_path

def on_request(ch, method, props, body):
    try:
        # Use a unique name for each processed image (e.g., using a counter)
        image_counter = on_request.counter if hasattr(on_request, 'counter') else 1
        save_path = f"processed_image_{image_counter}.jpg"
        on_request.counter = image_counter + 1
        
        result = process(body, save_path)
        with open(result, "rb") as image_file:
            image_str = base64.b64encode(image_file.read())
    except Exception as e:
        image_str = f'Error processing image: {str(e)}'

    ch.basic_publish(exchange='',
                     routing_key=props.reply_to,
                     properties=pika.BasicProperties(correlation_id=props.correlation_id),
                     body=image_str)
    ch.basic_ack(delivery_tag=method.delivery_tag)





save_folder = "save"  # Adjust this to your desired save folder

@app.post("/process_image")
async def process_image(file: UploadFile = File(...)):
    contents = await file.read()
    try:
        # Use a unique name for each processed image (e.g., using a counter)
        process_image.counter = process_image.counter + 1 if hasattr(process_image, 'counter') else 1
        save_path = os.path.join(save_folder, f"processed_image_{process_image.counter}.jpg")
        
        result_buffer = process(contents, save_path)
    except Exception as e:
        print(f"Error processing image: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Error processing image: {str(e)}")

    return StreamingResponse(BytesIO(result_buffer), media_type="image/jpeg")

@app.get("/")
async def main():
    content = """
    <body>
    <form action="/process_image" enctype="multipart/form-data" method="post">
    <input name="file" type="file" accept="image/*">
    <input type="submit">
    </form>
    </body>
    """
    return HTMLResponse(content)


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)