from flask import Flask, request, render_template, Response, jsonify
import cv2
import numpy as np
from ultralytics import YOLO
from paddleocr import PaddleOCR
from deepsort_tracker import Tracker
import os
from datetime import datetime
from collections import defaultdict

app = Flask(__name__)

# Initialize PaddleOCR
ocr = PaddleOCR(use_angle_cls=True, use_gpu=True, lang='en')

# Load YOLO models
coco_model = YOLO('yolov8m.pt')
license_plate_detector = YOLO('bestm.pt')

# Initialize the tracker
tracker = Tracker()

# Define vehicle classes
vehicles = [2, 3, 5, 7]

# Function to replace certain characters in OCR result
def replace_chars(input_string):
    chars_to_replace = ['0', 'o', 'O', 'Q']
    replacement_char = 'O'
    translation_table = str.maketrans(''.join(chars_to_replace), replacement_char * len(chars_to_replace))
    result_string = input_string.translate(translation_table)
    return result_string

latest_license_plate = {"license_plate": "", "timestamp": ""}

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/upload_video', methods=['POST'])
def upload_video():
    if 'video' not in request.files:
        return jsonify({"error": "No video file in request"}), 400

    file = request.files['video']
    file_path = os.path.join('uploads', file.filename)
    file.save(file_path)
    video_feed()
    get_license_plate()
    return jsonify({"video_path": file_path}), 200

def process_video_stream(file_path):
    global latest_license_plate
    cap = cv2.VideoCapture(file_path)
    temp = 0
    temp2 = " "
    ret = True

    while ret:
        ret, frame = cap.read()
        if not ret:
            break
        
        # Resize the frame to 640x480
        frame = cv2.resize(frame, (640, 480))
        
        # Detect vehicles using YOLO
        detections = coco_model(frame)[0]
        detections_ = []
        for detection in detections.boxes.data.tolist():
            x1, y1, x2, y2, score, class_id = detection
            if int(class_id) in vehicles:
                detections_.append([x1, y1, x2, y2, score])
        
        # Update SORT tracker with detections
        tracker.update(frame, detections_)
        
        # Detect license plates
        license_plates = license_plate_detector(frame)[0]
        for license_plate in license_plates.boxes.data.tolist():
            x1, y1, x2, y2, score, class_id = license_plate
            for track in tracker.tracks:
                bbox = track.bbox
                cx1, cy1, cx2, cy2 = bbox
                track_id = track.track_id
                if x1 > cx1 and y1 > cy1 and x2 < cx2 and y2 < cy2:
                    license_plate_crop = frame[int(y1):int(y2), int(x1):int(x2), :]
                    license_plate_crop_gray = cv2.cvtColor(license_plate_crop, cv2.COLOR_BGR2GRAY)
                    
                    if temp != track_id:
                        result = ocr.ocr(license_plate_crop_gray, cls=True)
                        if result:
                            for res in result:
                                if res:
                                    for line in res:
                                        text = line[1]
                                    text_str = replace_chars(str(text[0]))
                                    if text_str != temp2:
                                        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                                        latest_license_plate = {
                                            "license_plate": text_str,
                                            "timestamp": current_time
                                        }
                                        temp2 = text_str
                        temp = track_id
                    
                    cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
                    cv2.putText(frame, text_str, (int(x1), int(y1) - 5), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        
        ret, buffer = cv2.imencode('.jpg', frame)
        frame = buffer.tobytes()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

    cap.release()

@app.route('/video_feed')
def video_feed():
    file_path = request.args.get('file_path')
    return Response(process_video_stream(file_path), mimetype='multipart/x-mixed-replace; boundary=frame')

@app.route('/get_license_plate')
def get_license_plate():
    global latest_license_plate
    return jsonify(latest_license_plate)

if __name__ == '__main__':
    if not os.path.exists('uploads'):
        os.makedirs('uploads')
    app.run(debug=True)