import cv2
import numpy as np
import json

# Correcting the file path
cfg_path = r"D:\pyproject\yolo\yolov4.cfg"
weights_path = r"D:\pyproject\yolo\yolov4.weights"

# Load YOLO configuration and weights
net = cv2.dnn.readNet(weights_path, cfg_path)

# Load class labels
with open(r"D:\pyproject\yolo\coco.names", "r") as f:
    classes = [line.strip() for line in f.readlines()]

# Get output layers of the YOLO network
layer_names = net.getLayerNames()
output_layers = [layer_names[i - 1] for i in net.getUnconnectedOutLayers()]

# QR Code detector
qr_detector = cv2.QRCodeDetector()
qr_mode = True  # Start in QR Code detection mode

# Products data and QR code content
products = [
    {"id": 3, "name": "cell phone", "description": "Premium graphite pencils.", "price": "10.00", "stock": 300},
    {"id": 3, "name": "clock", "description": "Premium graphite pencils.", "price": "10.00", "stock": 300}
]

matched_qr_data = json.dumps(products, separators=(",", ":"))  # Expected QR Code Data
product_names = [product["name"] for product in products]  # Extract product names

# Initialize webcam
cap = cv2.VideoCapture(0)  # Use the default webcam (0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

print("🔍 Scanning QR Code... Please show the QR code to the camera.")

while qr_mode:
    ret, frame = cap.read()
    if not ret:
        print("⚠️ Error: Could not capture frame from webcam.")
        continue

    # Detect QR code
    data, bbox, _ = qr_detector.detectAndDecode(frame)

    if bbox is not None and data:  # QR Code detected
        bbox = bbox.astype(int)  # Convert float points to integers

        # Draw bounding box around QR code
        for i in range(len(bbox[0])):
            pt1 = tuple(bbox[0][i])  
            pt2 = tuple(bbox[0][(i + 1) % len(bbox[0])])  
            cv2.line(frame, pt1, pt2, (0, 255, 0), 2)

        # Display detected QR code data on screen
        cv2.putText(frame, f"QR Code: {data}", (20, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
        print(f"✅ QR Code Detected: {data}")

        if data == matched_qr_data:
            qr_mode = False
            print("🎯 QR Code matched. Switching to object detection mode.")
            break
        else:
            print("❌ QR Code did not match. Please show the correct QR code.")

    else:
        # Display message if QR code is not found
        cv2.putText(frame, "Show QR Code to the Camera", (20, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)

    # Show the live webcam feed
    cv2.imshow("QR Code Scanner", frame)

    # Press 'q' to manually exit QR code detection
    if cv2.waitKey(1) & 0xFF == ord('q'):
        cap.release()
        cv2.destroyAllWindows()
        exit("🚪 QR code scanning aborted.")

cv2.destroyAllWindows()  # Close QR scanning window

# Object Detection Mode
print("🚀 Starting Object Detection...")
while True:
    ret, frame = cap.read()
    if not ret:
        break

    height, width, _ = frame.shape

    # Prepare the image for YOLO
    blob = cv2.dnn.blobFromImage(frame, 0.00392, (416, 416), (0, 0, 0), True, crop=False)
    net.setInput(blob)

    # Perform forward pass to get detections
    outs = net.forward(output_layers)

    # Extract information from detections
    class_ids = []
    confidences = []
    boxes = []
    detected_labels = []  # Store detected object labels
    for out in outs:
        for detection in out:
            scores = detection[5:]
            class_id = np.argmax(scores)
            confidence = scores[class_id]
            if confidence > 0.5:  # Detection threshold
                center_x = int(detection[0] * width)
                center_y = int(detection[1] * height)
                w = int(detection[2] * width)
                h = int(detection[3] * height)

                # Rectangle coordinates
                x = int(center_x - w / 2)
                y = int(center_y - h / 2)
                boxes.append([x, y, w, h])
                confidences.append(float(confidence))
                class_ids.append(class_id)
                detected_labels.append(classes[class_id])  # Add detected label

    # Apply Non-Max Suppression to remove overlapping boxes
    indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)

    if len(indexes) > 0:  # Ensure indexes is not empty
        for i in indexes.flatten():
            x, y, w, h = boxes[i]
            label = str(classes[class_ids[i]])
            confidence = confidences[i]
            color = (0, 255, 0)  # Green

            # Draw rectangle and add numbering
            cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
            cv2.putText(frame, f"{label} {confidence:.2f}", (x, y - 10),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

    # Compare detected labels with product names
    if all(item in detected_labels for item in product_names):
        cv2.putText(frame, "✅ Success: All products detected!", (20, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
        print("✅ Success: All products detected. Now exit, please!")
    else:
        cv2.putText(frame, "❌ Show Your Purchased All Products!", (20, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)

    # Show the video feed with detections
    cv2.imshow("Object Detection", frame)

    # Break the loop if 'q' is pressed
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# Release the webcam and close all windows
cap.release()
cv2.destroyAllWindows()
