import cv2 
import numpy as np 
import os 
from typing import List ,Dict ,Optional 

from ..config import (
ULTRALYTICS_AVAILABLE ,
MODELS_DIR ,
COLORS ,
DEFAULT_CONF_THRESHOLD ,
)
from .yolo26 import YOLO26Detector 

if ULTRALYTICS_AVAILABLE :
    from ultralytics import YOLO 

class HybridLogoDetector :
    def __init__ (self ,
    coco_model_size :str ="nano",
    logo_model_path :Optional [str ]=None ,
    conf_threshold :float =DEFAULT_CONF_THRESHOLD ,
    device :str ="auto"):
        self .conf_threshold =conf_threshold 
        self .device =device 
        self .coco_detector =None 
        self .logo_model =None 

        if not ULTRALYTICS_AVAILABLE :
            raise RuntimeError ("Ultralytics not installed. Run: pip install ultralytics")

        print ("Loading YOLO26 COCO base model...")
        self .coco_detector =YOLO26Detector (
        model_size =coco_model_size ,
        conf_threshold =conf_threshold ,
        device =device 
        )

        if logo_model_path and os .path .exists (logo_model_path ):
            print (f"Loading logo model: {logo_model_path }")
            self .logo_model =YOLO (logo_model_path )
            print ("Logo model loaded!")
        else :
            default_logo_model =MODELS_DIR /"logo_detector.pt"
            if default_logo_model .exists ():
                print (f"Loading default logo model: {default_logo_model }")
                self .logo_model =YOLO (str (default_logo_model ))
                print ("Logo model loaded!")
            else :
                print ("No logo model found.")

        print ("Hybrid detector ready!")

    def detect (self ,
    frame :np .ndarray ,
    detect_objects :bool =True ,
    detect_logos :bool =True ,
    conf_threshold :Optional [float ]=None )->List [Dict ]:
        conf =conf_threshold if conf_threshold is not None else self .conf_threshold 
        all_detections =[]

        if detect_objects and self .coco_detector :
            object_detections =self .coco_detector .detect (frame ,conf_threshold =conf )
            for det in object_detections :
                det ["type"]="object"
            all_detections .extend (object_detections )

        if detect_logos and self .logo_model :
            logo_detections =self ._detect_logos (frame ,conf )
            for det in logo_detections :
                det ["type"]="logo"
            all_detections .extend (logo_detections )

        return all_detections 

    def _detect_logos (self ,frame :np .ndarray ,conf_threshold :float )->List [Dict ]:
        if self .logo_model is None :
            return []

        results =self .logo_model (
        frame ,
        conf =conf_threshold ,
        device =self .device if self .device !="auto"else None ,
        verbose =False 
        )

        detections =[]
        for result in results :
            boxes =result .boxes 
            if boxes is None :
                continue 

            for i in range (len (boxes )):
                xyxy =boxes .xyxy [i ].cpu ().numpy ()
                x1 ,y1 ,x2 ,y2 =map (int ,xyxy )
                conf_val =float (boxes .conf [i ].cpu ().numpy ())
                class_id =int (boxes .cls [i ].cpu ().numpy ())
                label =self .logo_model .names [class_id ]

                detections .append ({
                "bbox":(x1 ,y1 ,x2 ,y2 ),
                "label":label ,
                "confidence":conf_val ,
                "class_id":class_id ,
                "brand":label 
                })

        return detections 

    def draw_detections (self ,
    frame :np .ndarray ,
    detections :List [Dict ],
    show_labels :bool =True )->np .ndarray :
        result =frame .copy ()

        for det in detections :
            x1 ,y1 ,x2 ,y2 =det ["bbox"]
            label =det ["label"]
            conf =det ["confidence"]
            det_type =det .get ("type","object")

            if det_type =="logo":
                color =COLORS ["logo"]
            elif conf >0.7 :
                color =COLORS ["high_conf"]
            elif conf >0.5 :
                color =COLORS ["medium_conf"]
            else :
                color =COLORS ["low_conf"]

            cv2 .rectangle (result ,(x1 ,y1 ),(x2 ,y2 ),color ,2 )

            if show_labels :
                label_text =f"{label }: {conf :.2f}"
                (text_w ,text_h ),_ =cv2 .getTextSize (
                label_text ,cv2 .FONT_HERSHEY_SIMPLEX ,0.5 ,1 
                )
                cv2 .rectangle (
                result ,
                (x1 ,y1 -text_h -8 ),
                (x1 +text_w +4 ,y1 ),
                color ,
                -1 
                )
                cv2 .putText (
                result ,
                label_text ,
                (x1 +2 ,y1 -4 ),
                cv2 .FONT_HERSHEY_SIMPLEX ,
                0.5 ,
                (255 ,255 ,255 )if det_type =="logo"else (0 ,0 ,0 ),
                1 
                )

        return result 
