"""Deterministic binary segmentation baseline. No learned model or dataset."""
from __future__ import annotations

from typing import cast

import cv2
import numpy as np
from numpy.typing import NDArray

ByteImage = NDArray[np.uint8]
Mask = NDArray[np.bool_]


def scene() -> tuple[ByteImage, Mask]:
    """Return a uint8 (12,12) scene and independently defined rectangle target."""
    target: Mask = np.zeros((12, 12), dtype=np.bool_)
    target[3:9, 3:9] = True
    gray: ByteImage = np.where(target, 180, 30).astype(np.uint8)
    gray[1, 1] = 220  # distractor: bright, but not part of the target
    gray[5, 5] = 40   # corruption: dark, but still part of the target
    return gray, target

# region threshold
def threshold_mask(gray: ByteImage, threshold: int = 100) -> Mask:
    """Nonempty uint8 (H,W) -> bool (H,W), using STRICT greater-than."""
    if gray.dtype != np.uint8 or gray.ndim != 2 or gray.size == 0:
        raise ValueError("Expected a nonempty uint8 grayscale image")
    if not 0 <= threshold <= 255:
        raise ValueError("Threshold must be in [0,255]")
    mask: Mask = gray > threshold
    _, encoded = cv2.threshold(gray, threshold, 255, cv2.THRESH_BINARY)
    np.testing.assert_array_equal(mask, encoded != 0)
    return mask
# endregion threshold

# region morphology
def clean_mask(mask: Mask) -> tuple[Mask, Mask]:
    """Return closing then opening, 3x3 square, outside-image background=0."""
    if mask.dtype != np.bool_ or mask.ndim != 2 or mask.size == 0:
        raise ValueError("Expected a nonempty bool mask")
    encoded: ByteImage = mask.astype(np.uint8) * np.uint8(255)
    kernel: ByteImage = np.ones((3, 3), dtype=np.uint8)
    closed_u8: ByteImage = cast(ByteImage, cv2.morphologyEx(
        encoded, cv2.MORPH_CLOSE, kernel,
        borderType=cv2.BORDER_CONSTANT, borderValue=0,
    ))
    opened_u8: ByteImage = cast(ByteImage, cv2.morphologyEx(
        closed_u8, cv2.MORPH_OPEN, kernel,
        borderType=cv2.BORDER_CONSTANT, borderValue=0,
    ))
    closed: Mask = closed_u8 != 0
    cleaned: Mask = opened_u8 != 0
    return closed, cleaned
# endregion morphology
