import streamlit as st
import cv2
from ultralytics import YOLO
from paddleocr import PaddleOCR
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing.image import img_to_array
import numpy as np
import re
from datetime import datetime
import pandas as pd

# Load YOLO models
brand_model = YOLO('b.pt')  # Replace 'b.pt' with the correct path to your YOLO model for brands
ocr = PaddleOCR(lang='en')  # Initialize PaddleOCR
fruit_model = load_model('DenseNet20_model.h5')  # Replace with the correct path to your fruit freshness model
object_model = YOLO('yolov5s.pt')  # Add object detection model

# Class names for freshness detection
class_names = {
    0: 'Banana_Bad', 1: 'Banana_Good', 2: 'Fresh', 3: 'FreshCarrot', 4: 'FreshCucumber',
    5: 'FreshMango', 6: 'FreshTomato', 7: 'Guava_Bad', 8: 'Guava_Good', 9: 'Lime_Bad',
    10: 'Lime_Good', 11: 'Rotten', 12: 'RottenCarrot', 13: 'RottenCucumber',
    14: 'RottenMango', 15: 'RottenTomato', 16: 'freshBread', 17: 'rottenBread'
}

# Custom CSS for styling
st.markdown("""
    <style>
    .main {
        background-color: #f0f2f6;
        padding: 20px;
        border-radius: 10px;
    }
    .stButton>button {
        background-color: #4CAF50;
        color: white;
        border-radius: 8px;
        padding: 10px 24px;
        font-size: 16px;
        margin: 10px 0;
    }
    .stButton>button:hover {
        background-color: #45a049;
    }
    .stSidebar {
        background-color: #2c3e50;
        color: white;
    }
    .stSidebar .stSelectbox {
        color: black;
    }
    h1, h2, h3, h4, h5, h6 {
        color: #2c3e50;
    }
    </style>
""", unsafe_allow_html=True)

# Helper function: Extract expiry dates
def extract_expiry_dates(text):
    patterns = [
        r'(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',       # 20/07/2024 or 20-07-2024
        r'(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2})',       # 20/07/24 or 20-07-24
        r'(\d{1,2}\s*[A-Za-z]{3,}\s*\d{4})',       # 20 MAY 2024
        r'([A-Za-z]{3,}\s*\d{1,2}[,\s]*\d{4})',    # July 20, 2024
        r'(\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2})',       # 2024/07/20 or 2024-07-20
        r'([A-Za-z]{3}[\-]\d{1,2}[\-]\d{4})',
        r'(?:exp(?:iry)?\.?\s*date\s*[:\-]?\s*.*?(\d{2}[\/\-]\d{2}[\/\-][0O]\d{2}))',  # Expiry Date: 20/07/2O24
    r'(?:exp(?:iry)?\.?\s*date\s*[:\-]?\s*.*?(\d{2}[\/\-]\d{2}[\/\-]\d{4}))',  # Expiry Date: 20/07/2024
    r'(?:exp(?:iry)?\.?\s*date\s*[:\-]?\s*.*?(\d{2}[\/\-]\d{2}[\/\-][0O]\d{2}))',  # Expiry Date: 20/07/2O24
    r'(?:exp(?:iry)?\.?\s*date\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*[0O]\d{2}))',  # Expiry Date: 20 MAY 2O24
    r'(?:exp(?:iry)?\.?\s*date\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*\d{4}))',  # Expiry Date: 20 MAY 2024
    r'(?:exp(?:iry)?\.?\s*date\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*[0O]\d{2}))',  # Expiry Date: 20 MAY 2O24
    r'(?:exp(?:iry)?\.?\s*date\s*[:\-]?\s*.*?(\d{4}[\/\-]\d{2}[\/\-][0O]\d{2}))',  # Expiry Date: 2024/07/2O24
    r'(?:exp(?:iry)?\.?\s*date\s*[:\-]?\s*.*?(\d{4}[\/\-]\d{2}[\/\-]\d{2}))',  # Expiry Date: 2024/07/20
    r'(?:best\s*before\s*[:\-]?\s*.*?(\d{4}))',  # Best Before: 2025
    r'(?:best\s*before\s*[:\-]?\s*.*?(\d{2}[\/\-]\d{2}[\/\-][0O]\d{2}))',  # Best Before: 20/07/2O24
    r'(?:best\s*before\s*[:\-]?\s*.*?(\d{2}[\/\-]\d{2}[\/\-]\d{4}))',  # Best Before: 20/07/2024
    r'(?:best\s*before\s*[:\-]?\s*.*?(\d{2}[\/\-]\d{2}[\/\-][0O]\d{2}))',  # Best Before: 20/07/2O24
    r'(?:best\s*before\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*[0O]\d{2}))',  # Best Before: 20 MAY 2O24
    r'(?:best\s*before\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*\d{4}))',  # Best Before: 20 MAY 2024
    r'(?:best\s*before\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*[0O]\d{2}))',  # Best Before: 20 MAY 2O24
    r'(?:best\s*before\s*[:\-]?\s*.*?(\d{4}[\/\-]\d{2}[\/\-][0O]\d{2}))',  # Best Before: 2024/07/2O24
    r'(?:best\s*before\s*[:\-]?\s*.*?(\d{4}[\/\-]\d{2}[\/\-]\d{2}))',  # Best Before: 2024/07/20
    r'(?:best\s*before\s*[:\-]?\s*.*?(\d{1,2}\d{2}\d{2}))', 
    r'(?:best\s*before\s*[:\-]?\s*(\d{6}))',
    r'(?:consume\s*before\s*[:\-]?\s*.*?(\d{1,2}[A-Za-z]{3,}[0O]\d{2}))',  # Consume Before: 3ODEC2O24
    r'(?:consume\s*before\s*[:\-]?\s*.*?(\d{1,2}[A-Za-z]{3,}\d{2}))',  # Consume Before: 30DEC23
    r'(?:consume\s*before\s*[:\-]?\s*.*?(\d{2}[\/\-]\d{2}[\/\-][0O]\d{2}))',  # Consume Before: 20/07/2O24
    r'(?:consume\s*before\s*[:\-]?\s*.*?(\d{2}[\/\-]\d{2}[\/\-]\d{4}))',  # Consume Before: 20/07/2024
    r'(?:consume\s*before\s*[:\-]?\s*.*?(\d{2}[\/\-]\d{2}[\/\-][0O]\d{2}))',  # Consume Before: 20/07/2O24
    r'(?:consume\s*before\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*[0O]\d{2}))',  # Consume Before: 20 MAY 2O24
    r'(?:consume\s*before\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*\d{4}))',  # Consume Before: 20 MAY 2024
    r'(?:consume\s*before\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*[0O]\d{2}))',  # Consume Before: 20 MAY 2O24
    r'(?:consume\s*before\s*[:\-]?\s*.*?(\d{4}[\/\-]\d{2}[\/\-][0O]\d{2}))',  # Consume Before: 2024/07/2O24
    r'(?:consume\s*before\s*[:\-]?\s*.*?(\d{4}[\/\-]\d{2}[\/\-]\d{2}))',  # Consume Before: 2024/07/20
    r'(?:exp\s*[:\-]?\s*.*?(\d{2}[\/\-]\d{2}[\/\-][0O]\d{2}))',  # Exp: 20/07/2O24
    r'(?:exp\s*[:\-]?\s*.*?(\d{2}[\/\-]\d{2}[\/\-]\d{4}))',  # Exp: 20/07/2024
    r'(?:exp\s*[:\-]?\s*.*?(\d{2}[\/\-]\d{2}[\/\-][0O]\d{2}))',  # Exp: 20/07/2O24
    r'(?:exp\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*[0O]\d{2}))',  # Exp: 20 MAY 2O24
    r'(?:exp\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*\d{4}))',  # Exp: 20 MAY 2024
    r'(?:exp\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*[0O]\d{2}))',  # Exp: 20 MAY 2O24
    r'(?:exp\s*[:\-]?\s*.*?(\d{4}[\/\-]\d{2}[\/\-][0O]\d{2}))',  # Exp: 2024/07/2O24
    r'(?:exp\s*[:\-]?\s*.*?(\d{4}[\/\-]\d{2}[\/\-]\d{2}))',  # Exp: 2024/07/20
    r'Exp\.Date\s+(\d{2}[A-Z]{3}\d{4})',
    r'(?:exp\s*\.?\s*date\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*[0O]\d{2}))',  # Exp. Date: 16 MAR 2O30 (with typo)
    r'(?:exp\s*\.?\s*date\s*[:\-]?\s*.*?(\d{2}[\/\-]\d{2}[\/\-][0O]\d{2}))',  # Exp. Date: 15/12/2O30 (with typo)
    r'(?:exp\s*\.?\s*date\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*[0O]\d{2}))',  # Exp. Date: 15 MAR 2O30 (with typo)
    r'(?:exp\s*\.?\s*date\s*[:\-]?\s*.?(\d{2}\s[A-Za-z]{3,}\s*[0O]\d{2}))',  # Exp. Date cdsyubfuyef 15 MAR 2O30 (with typo)
    r'(\d{2}[\/\-]\d{2}[\/\-]\d{4})',  # 20/07/2024
    r'(\d{2}[\/\-]\d{2}[\/\-]\d{2})',  # 20/07/24
    r'(\d{2}\s*[A-Za-z]{3,}\s*\d{4})',  # 20 MAY 2024
    r'(\d{2}\s*[A-Za-z]{3,}\s*\d{2})',  # 20 MAY 24
    r'(\d{4}[\/\-]\d{2}[\/\-]\d{2})',  # 2024/07/20
    r'(\d{4}[\/\-]\d{2}[\/\-]\d{2})',  # 2024-07-20
    r'(\d{4}[A-Za-z]{3,}\d{2})',  # 2024MAY20
    r'(\d{2}[A-Za-z]{3,}\d{4})',  # 20MAY2024
    r'(?:exp\.?\s*date\s*[:\-]?\s*(\d{2}\s*[A-Za-z]{3,}\s*(\d{4}|\d{2})))',
    r'(?:exp\.?\s*date\s*[:\-]?\s*(\d{2}\s*\d{2}\s*\d{4}))',  # Exp. Date: 20 05 2025
    r'(\d{4}[A-Za-z]{3}\d{2})',  # 2025MAY11
    r'(?:best\s*before\s*[:\-]?\s*(\d+)\s*(days?|months?|years?))',  # Best Before: 6 months
    r'(?:best\s*before\s*[:\-]?\s*(three)\s*(months?))',
    r'(\b(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b\s*\d{4})',
    r'\bUSE BY\s+(\d{1,2}[A-Za-z]{3}\d{4})\b',
    r'Exp\.Date\s*(\d{2}[A-Z]{3}\d{4})',
    r'EXP:\d{4}/\d{2}/\d{4}/\d{1}/[A-Z]',     # JAN-15-2024
    r'USE BY[:\-]?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # Use by date
        r'BEST BEFORE[:\-]?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # Best before date
        r'EXPIRY DATE[:\-]?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # Expiry Date
        r'EXPIRY[:\-]?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # Expiry
        r'EXP[:\-]?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # Exp
        r'VALID UNTIL[:\-]?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # Valid Until
        r'CONSUME BY[:\-]?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # Consume By
        r'EXPIRES ON[:\-]?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # Expires On
        # DDMMMYYYY format
        r'(\d{1,2}[A-Za-z]{3}\d{4})',  # DDMMMYYYY format
        # Short year formats
        r'(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2})',  # Short year date format (DD/MM/YY)
        r'(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # General date format (DD/MM/YYYY)
        # Year-month-day formats
        r'(\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2})',  # Year-month-day format (YYYY/MM/DD)
        # Month/Year formats
        r'(\d{1,2}[\/\-]\d{1,2})',  # MM/DD format
        r'(\d{1,2}[\/\-]\d{2})',  # MM/YY format
        # Month name formats
        r'(\d{1,2}\s*[A-Za-z]{3,}\s*\d{4})',  # Month name with day and year
        r'(\d{1,2}\s*[A-Za-z]{3,}\s*\d{2})',  # Month name with day and short year
        # Year with month name
        r'(\d{4}[A-Za-z]{3,}\d{1,2})',  # Year with month name
        r'(\d{1,2}[A-Za-z]{3,}\d{4})',  # Day with month name and full year
        # Additional formats
        r'(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2})',  # MM/DD/YY format
        r'(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # MM/DD/YYYY format
        r'(\d{1,2}[\/\-]\d{1,2})',  # MM/DD format
        r'(\d{1,2}[\/\-]\d{2})',  # MM/YY format
        # Best before phrases
        r'Best before (\d+) months',  # Best before in months
        r'Expiration Date[:\-]?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # Expiration Date
        r'Expires[:\-]?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # Expires
        # Additional variations
        r'(\d{1,2}\s*[A-Za-z]{3,}\s*\d{4})',  # Month name with day and year
        r'(\d{1,2}\s*[A-Za-z]{3,}\s*\d{2})',  # Month name with day and short year
        # More variations
        r'(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # MM/DD/YYYY format
        r'(\d{1,2}[\/\-]\d{1,2})',  # MM/DD format
        r'(\d{1,2}[\/\-]\d{2})',  # MM/YY format
        # Additional expiry phrases
        r'(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # Expiry in various formats
        r'(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2})',  # Expiry in short year formats
        r'(\d{1,2}[\/\-]\d{1,2})',  # Expiry in MM/DD format
        r'(\d{1,2}[\/\-]\d{2})',  # Expiry in MM/YY format
        # Additional phrases
        r'(\d{1,2}\s*[A-Za-z]{3,}\s*\d{4})',  # Month name with day and year
        r'(\d{1,2}\s*[A-Za-z]{3,}\s*\d{2})',  # Month name with day and short year
        r'(\d{4}[A-Za-z]{3,}\d{1,2})',  # Year with month name
        r'(\d{1,2}[A-Za-z]{3,}\d{4})',  # Day with month name and full year
        # Additional expiry phrases
        r'(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',  # Expiry in various formats
        r'(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2})',  # Expiry in short year formats
        r'(\d{1,2}[\/\-]\d{1,2})',  # Expiry in MM/DD format
        r'(\d{1,2}[\/\-]\d{2})',  # Expiry in MM/YY format
    ]
    dates = []
    for pattern in patterns:
        matches = re.findall(pattern, text)
        dates.extend(matches)

    unique_dates = sorted(dates, key=lambda x: len(x), reverse=True)
    return [unique_dates[0]] if unique_dates else []  # Return the most likely date

# Helper function: Preprocess image for fruit freshness
def preprocess_image(image):
    img = cv2.resize(image, (128, 128))
    img_array = img_to_array(img)
    img_array = np.expand_dims(img_array, axis=0)
    img_array = img_array / 255.0
    return img_array

# Helper function: Calculate days to expiry
def calculate_days_to_expiry(expiry_dates):
    results = []
    today = datetime.now()
    for date_str in expiry_dates:
        try:
            if '/' in date_str or '-' in date_str:
                if len(date_str.split('/')[-1]) == 2 or len(date_str.split('-')[-1]) == 2:
                    date_obj = datetime.strptime(date_str, '%d/%m/%y') if '/' in date_str else datetime.strptime(date_str, '%d-%m-%y')
                else:
                    date_obj = datetime.strptime(date_str, '%d/%m/%Y') if '/' in date_str else datetime.strptime(date_str, '%d-%m-%Y')
            else:
                date_obj = datetime.strptime(date_str, '%d %B %Y')

            delta = (date_obj - today).days
            if delta >= 0:
                results.append(f"{date_str}: {delta} days to expire")
            else:
                results.append(f"{date_str}: Expired")
        except ValueError:
            results.append(f"{date_str}: Invalid date format")
    return results

# Initialize session state
if 'uploaded_file' not in st.session_state:
    st.session_state['uploaded_file'] = None

# Streamlit App
st.title("Flipkart Grid")

# Sidebar options
app_mode = st.sidebar.selectbox(
    "Choose the mode",
    ["Home", "Brand & Text Detection", "Fruit Freshness Detection", "Object Detection"],
    on_change=lambda: st.session_state.update({'uploaded_file': None})  # Reset uploaded file on mode change
)

if app_mode == "Home":
    st.markdown("""
    ## Welcome to the Detection App
    Use the sidebar to choose between:
    - *Brand & Text Detection*: Detect brands, extract text, and identify expiry dates from uploaded images.
    - *Fruit Freshness Detection*: Detect and classify the freshness of fruits from uploaded images.
    - *Object Detection*: Detect objects in uploaded images.
    """)

else:
    st.header(app_mode)
    uploaded_file = st.file_uploader("Upload an image", type=["jpg", "jpeg", "png"], key=app_mode)

    if uploaded_file is not None:
        st.session_state['uploaded_file'] = uploaded_file

    if st.session_state['uploaded_file'] is not None:
        file_bytes = np.asarray(bytearray(st.session_state['uploaded_file'].read()), dtype=np.uint8)
        image = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR)

        if app_mode == "Brand & Text Detection":
            # Brand detection
            results = brand_model.predict(source=image, stream=False)
            detected_image = results[0].plot()

            # OCR for text extraction
            _, img_buffer = cv2.imencode('.jpg', image)
            ocr_result = ocr.ocr(img_buffer.tobytes())
            if ocr_result and isinstance(ocr_result[0], list) and len(ocr_result[0]) > 0:
                extracted_text = ' '.join([line[1][0] for line in ocr_result[0]])
                expiry_dates = extract_expiry_dates(extracted_text)
                expiry_info = calculate_days_to_expiry(expiry_dates)
            else:
                extracted_text = "No text detected"
                expiry_dates = []
                expiry_info = []

            # Count objects
            object_counts = {}
            for box in results[0].boxes.data.cpu().numpy():
                label = results[0].names[int(box[5])]
                object_counts[label] = object_counts.get(label, 0) + 1

            # Display results
            st.image(cv2.cvtColor(detected_image, cv2.COLOR_BGR2RGB), caption="Detected Image")
            st.markdown(f"*Extracted Text:* {extracted_text}")
            st.markdown(f"*Expiry Dates:*")
            if expiry_info:
                for info in expiry_info:
                    st.markdown(f"- {info}")
            else:
                st.markdown("None")
            st.markdown("*Object Counts:*")
            for label, count in object_counts.items():
                st.markdown(f"- {label}: {count}")

        elif app_mode == "Fruit Freshness Detection":
            # Preprocess and predict
            img_array = preprocess_image(image)
            predictions = fruit_model.predict(img_array)
            predicted_class = np.argmax(predictions, axis=1)[0]
            label = class_names[predicted_class]
            confidence = predictions[0][predicted_class] * 100

            # Display results
            st.image(cv2.cvtColor(image, cv2.COLOR_BGR2RGB), caption="Uploaded Image")
            st.markdown(f"*Label:* {label}")
            st.markdown(f"*Confidence:* {confidence:.2f}%")

        elif app_mode == "Object Detection":
            # Object Detection
            results = object_model.predict(source=image, stream=False)
            detected_objects = []

            for result in results:
                boxes = result.boxes.data.cpu().numpy()
                for box in boxes:
                    class_id = int(box[5])
                    confidence = box[4]  # Assuming the confidence score is at index 4
                    detected_objects.append((result.names[class_id], confidence))

                    # Draw bounding box and label on the image
                    x1, y1, x2, y2 = map(int, box[:4])
                    label = f"{result.names[class_id]} {confidence * 100:.2f}%"
                    cv2.rectangle(image, (x1, y1), (x2, y2), (255, 0, 0), 2)
                    cv2.putText(image, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)

            # Convert the image back to RGB for display in Streamlit
            image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
            st.image(image_rgb, caption='Detected Objects', use_container_width=True)

            # Count occurrences and average confidence of each object
            object_data = {}
            for obj, confidence in detected_objects:
                if obj in object_data:
                    object_data[obj]['count'] += 1
                    object_data[obj]['total_confidence'] += confidence
                else:
                    object_data[obj] = {'count': 1, 'total_confidence': confidence}

            # Prepare data for display
            object_display_data = [
                {'Object': obj, 'Count': data['count'], 'Average Confidence': data['total_confidence'] / data['count']}
                for obj, data in object_data.items()
            ]

            # Display detected objects in a table with column names
            st.write("Detected Objects and Counts:")
            st.table(pd.DataFrame(object_display_data))