from .ImageManipulation import ImageManipulation
from ImageContainer import ImageContainer
from typing import Any, List
from utils.image_utils import pil_to_cv2, cv2_to_pil
import cv2


class GaussianBlur(ImageManipulation):
    def getManipulationName(self) -> str:
        return "Gaussian Blur"

    def getParameters(self) -> List[str]:
        return ["ksize"]  # odd int

    def manipulateImage(self, image: ImageContainer, parameters: Any) -> None:
        if image is None or image.getImage() is None:
            return
        pil_img = image.getImage()
        ksize = 5
        if isinstance(parameters, dict) and parameters.get("ksize"):
            ksize = int(parameters.get("ksize"))
        if ksize % 2 == 0:
            ksize += 1
        cv_img = pil_to_cv2(pil_img)
        blurred = cv2.GaussianBlur(cv_img, (ksize, ksize), 0)
        image._imageData = cv2_to_pil(blurred)


class SobelEdge(ImageManipulation):
    def getManipulationName(self) -> str:
        return "Sobel Edge"

    def getParameters(self) -> List[str]:
        return ["dx", "dy", "ksize"]

    def manipulateImage(self, image: ImageContainer, parameters: Any) -> None:
        if image is None or image.getImage() is None:
            return
        pil_img = image.getImage()
        cv_img = pil_to_cv2(pil_img)
        gray = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
        dx = int(parameters.get("dx", 1)) if isinstance(parameters, dict) else 1
        dy = int(parameters.get("dy", 0)) if isinstance(parameters, dict) else 0
        ksize = int(parameters.get("ksize", 3)) if isinstance(parameters, dict) else 3
        sobel = cv2.Sobel(gray, cv2.CV_64F, dx, dy, ksize=ksize)
        abs_sobel = cv2.convertScaleAbs(sobel)
        image._imageData = cv2_to_pil(abs_sobel)


class BinaryThreshold(ImageManipulation):
    def getManipulationName(self) -> str:
        return "Binary Threshold"

    def getParameters(self) -> List[str]:
        return ["thresh"]

    def manipulateImage(self, image: ImageContainer, parameters: Any) -> None:
        if image is None or image.getImage() is None:
            return
        pil_img = image.getImage()
        cv_img = pil_to_cv2(pil_img)
        gray = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
        thresh_val = int(parameters.get("thresh", 127)) if isinstance(parameters, dict) else 127
        _, thresh = cv2.threshold(gray, thresh_val, 255, cv2.THRESH_BINARY)
        image._imageData = cv2_to_pil(thresh)


class HistogramThreshold(ImageManipulation):
    def getManipulationName(self) -> str:
        return "Histogram Threshold"

    def getParameters(self) -> List[str]:
        return []

    def manipulateImage(self, image: ImageContainer, parameters: Any) -> None:
        if image is None or image.getImage() is None:
            return
        pil_img = image.getImage()
        cv_img = pil_to_cv2(pil_img)
        gray = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
        # Otsu's threshold as histogram-based method
        _, otsu = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
        image._imageData = cv2_to_pil(otsu)

