from enum import Enum
from dataclasses import dataclass, field
from typing import List, Optional
from ..dao import AbstractRequest, StorageKey

class Info(Enum):
    COMPOUND = "COMPOUND"
    CROP = "CROP"
    FIND = "FIND"
    HTQUANT = "HTQUANT"
    ALIGNMENT = "ALIGNMENT"
    EDOF = "EDOF"
    KIDNEY_CLASSIFIER = "KIDNEY_CLASSIFIER"
    DECONVOLUTION = "DECONVOLUTION"
    YOLO_SEGDETECT = "YOLO_SEGDETECT"
    RETINAL_LAYER = "RETINAL_LAYER"
    STAIN_ADAPTER = "STAIN_ADAPTER"
    UNKNOWN = "UNKNOWN"
    CONVERT = "CONVERT"


@dataclass
class AlignmentRequest(AbstractRequest):

    info: Optional[Info] = field(default_factory=lambda: Info.ALIGNMENT)

    # Inputs
    align: Optional[StorageKey] = None
    reference: Optional[StorageKey] = None
    shg: Optional[StorageKey] = None

    # Outputs
    siftOutput: Optional[StorageKey] = None
    overlayedResult: Optional[StorageKey] = None

    # New parameters
    transform: Optional[bool] = True
    flip: Optional[bool] = True
    downsample: Optional[bool] = False
    max_size: Optional[int] = 9e7
    gamma: Optional[float] = 1.0

    resizedN: Optional[StorageKey] = None
    resizedSF: Optional[StorageKey] = None

    # Test parameters local to this repo,
    # not in the json used on the server.
    test: Optional[bool] = False

@dataclass(kw_only=True)
class EdofRequest(AbstractRequest):
    
    info: Optional[Info] = field(default_factory=lambda: Info.EDOF)
    
    # Inputs
    inputFiles: List[StorageKey]
    outputPath: StorageKey

    inputZmap: Optional[StorageKey] = None

    # Size of kernel used for computation of image gradients.Must be 1, 3, 5, 7.
    gradientKernel: Optional[int] = 5
    # Size of median filter used to reduce noise in the z-map. Must be 0, 3 or 5
    imageNoiseFilter: Optional[int] = 3
    # Size of median filter used to reduce noise in the z-map. Must be 0, 3 or 5
    zmapNoiseFilter: Optional[int] = 3
    # zmap lowpass filter object size.
    lowPass: Optional[float] = 2.0

    # Test parameters local to this repo,
    # not in the json used on the server.
    test: Optional[bool] = False


@dataclass(kw_only=True)
class DeconvolutionRequest(AbstractRequest):
    
    info: Optional[Info] = field(default_factory=lambda: Info.DECONVOLUTION)
    
    # Inputs
    inputPath: Optional[StorageKey] = None
    stain1: str | tuple[float, float, float] = "hematoxylin"
    stain2: str | tuple[float, float, float] = "eosin"
    stain1Max: float = 2.0
    stain2Max: float = 1.0
    alpha: int = 1
    beta: float = 0.15
    intensityNorm: int = 240
    grayscale: bool = False
    # Outputs
    stain1ImageOutput: Optional[StorageKey] = None
    stain2ImageOutput: Optional[StorageKey] = None
    normalizedImageOutput: Optional[StorageKey] = None
    imageStackOutput: Optional[StorageKey] = None

    # Test parameters local to this repo,
    # not in the json used on the server.
    test: Optional[bool] = False
    
@dataclass(kw_only=True)
class YoloSegdetectRequest(AbstractRequest):
    
    info: Optional[Info] = field(default_factory=lambda: Info.YOLO_SEGDETECT)

    # Inputs
    inputPaths: Optional[List[StorageKey]] = None
    outputPath: Optional[StorageKey] = None
    weightsPath: Optional[str] = None
    downsamplingFactor: Optional[int] = 5
    visualize: Optional[bool] = False
    overlapX: Optional[int] = 0
    overlapY: Optional[int] = 0
    confidence: Optional[float] = 0.6
    iouThreshold: Optional[float] = 0.5
    nmsThreshold: Optional[float] = 0.3
    saveSegment: Optional[bool] = False
    level: Optional[int] = 2

    # Set if we want the activity to store the
    # classification to claris to be run.
    db_upsert: Optional[bool] = False

    # Test parameters local to this repo,
    # not in the json used on the server.
    test: Optional[bool] = False

