from pathlib import Path

import numpy as np
import numpy.typing as npt
from anomalib.models import Patchcore
from dopt_basics import result_pattern

from dopt_sensor_anomalies import types as t

def midpoint(
    pt_A: npt.NDArray[np.floating],
    pt_B: npt.NDArray[np.floating],
) -> tuple[float, float]:
    """to identify the midpoint of a 2D area

    Parameters
    ----------
    pt_A : npt.NDArray[np.floating]
        tuple of coordinates x, y; shape (2, )
    pt_B : npt.NDArray[np.floating]
        tuple of coordinates x, y; shape (2, )

    Returns
    -------
    tuple[float, float]
        tuple of midpoint coordinates
    """
    ...

def check_box_redundancy(
    box_1: t.Box,
    box_2: t.Box,
    tolerance: float = 5.0,
) -> bool:
    """to check if bounding box has already been identified and is just a redundant one

    Parameters
    ----------
    box_1 : t.Box
        tuple of box values: ((center_x, center_y), (width, height), angle)
    box_2 : t.Box
        tuple of box values: ((center_x, center_y), (width, height), angle)
    tolerance : float, optional
        distance threshold for width and height, by default 5.0

    Returns
    -------
    bool
        redundancy evaluation
    """
    ...

def measure_length(
    img_path: Path,
    pixels_per_metric_X: float,
    pixels_per_metric_Y: float,
) -> tuple[t.ExportData, t.SensorImages]:
    """detect and measure the size of the electrodes

    Parameters
    ----------
    img_path : Path
        path to file to analyse
    pixels_per_metric_X : float
        scaling parameter x dimension, Pixels per micrometer in image
    pixels_per_metric_Y : float
        scaling parameter y dimension, Pixels per micrometer in image

    Returns
    -------
    tuple[t.ExportData, t.SensorImages]
        t.ExportData: (TypedDict) data to save as CSV according to requirements, contains
        strings for sensor sizes and anomaly detection results for the left and right hand
        sensor respectively
        t.SensorImages: (TypedDict) contains left and right image corresponding to each sensor

    Raises
    ------
    errors.ImageNotReadError
        image was not read successfully
    errors.ContourCalculationError
        during contour detection there were several possible error causes
    errors.InvalidElectrodeCount
        an invalid number of electrodes were detected
    """
    ...

def infer_image(
    image: npt.NDArray[np.uint8],
    model: Patchcore,
    anomaly_threshold: float,
) -> t.InferenceResult:
    """evaluate one image

    Parameters
    ----------
    image : npt.NDArray[np.uint8]
        represents image to be checked for anomalies
    model : Patchcore
        (loaded PyTorch state dictionary): model for anomaly detection

    Returns
    -------
    t.InferenceResult
        contains:
        img (numpy.ndarray)
        anomaly_map_resized (numpy.ndarray): heatmap to visualize detected anomalies
        anomaly_score (float): evaluation metric, in [0, 1] with close to 0 being no
            anomaly detected
        anomaly_label (bool): anomaly detected (1) or not (0)
    """
    ...

def anomaly_detection(
    img_path: Path,
    detection_models: t.DetectionModels,
    export_data: t.ExportData,
    sensor_images: t.SensorImages,
    anomaly_threshold: float,
) -> None:
    """load the model, call function for anomaly detection and store the results

    Parameters
    ----------
    img_path : Path
        path to file to analyse
    detection_models : t.DetectionModels
        collection of model paths for the left and right sensor
    export_data: t.ExportData,
        (TypedDict) data to save as CSV according to requirements, contains strings for sensor
        sizes and anomaly detection results for the left and right hand sensor respectively
    sensor_images : t.SensorImages
        _description_
    """
    ...

@result_pattern.wrap_result(100)
def pipeline(
    user_img_path: str,
    pixels_per_metric_X: float,
    pixels_per_metric_Y: float,
    anomaly_threshold: float,
) -> None:
    """full pipeline defined by the agreed requirements
    wrapped as result pattern, handle errors on higher abstraction level

    Parameters
    ----------
    user_img_path : str
        file path to the image which is to be analysed
    pixels_per_metric_X : float
        calibration value for the x axis to measure the size of the electrodes
    pixels_per_metric_Y : float
        calibration value for the y axis to measure the size of the electrodes

    Raises
    ------
    FileNotFoundError
        provided image path was not found
    """
