import enum
import itertools
from dataclasses import dataclass
import datetime
from typing import List, Set, Dict, Tuple, Optional, Any


@enum.unique
class Opinion(enum.Enum):
    """Opinion after a procedure"""
    A1 = 'Assess normal'
    A2 = 'Assess benign'
    A3 = "Assess uncert'n"
    A4 = 'Assess suspic'
    A5 = 'Assess malig'
    B1 = 'Unsatis/Normal'
    B2 = 'Benign'
    B3 = 'Benign unc mal'
    B4 = 'Susp of malig'
    B5 = 'Malignant'
    BA = 'Clinical'
    C1 = 'Cyt unsatis'
    C2 = 'Cyt benign'
    C3 = 'Cyt atypia'
    C4 = 'Cyt susp malig'
    C5 = 'Cyt malig'
    H0 = 'Hist unreported'
    H1 = 'Histol normal'
    H2 = 'Histol benign'
    H5 = 'Hist malignant'
    I1 = 'Imaging normal'
    I2 = 'Imaging benign'
    I3 = 'Imaging uncertain'
    I4 = 'Imaging suspicious'
    I5 = 'Imaging malig'
    MRI1 = 'MRI normal'
    MRI2 = 'MRI benign'
    MRI3 = 'MRI indeterminate'
    MRI4 = 'MRI suspicious'
    MRI5 = 'MRI malig'
    OB = 'O Benign'
    OM = 'O Malignant'
    ON = 'O Normal'
    OS = 'O Suspicious'
    OU = 'O Uncertain'
    P1 = 'Clin normal'
    P2 = 'Clin benign'
    P3 = 'Clin uncertain'
    P4 = 'Clin suspicious'
    P5 = 'Clin malignant'
    R1 = 'Rad normal'
    R2 = 'Rad benign'
    R3 = 'Rad uncertain'
    R4 = 'Rad suspicious'
    R5 = 'Rad malig'
    RB = 'R Benign'
    RM = 'R Malignant'
    RN = 'R Normal'
    RO = 'R Unreported'
    RS = 'R Suspicious'
    RU = 'R Uncertain'
    SH = 'History suspic'
    U1 = 'USS normal'
    U2 = 'USS benign'
    U3 = 'USS uncertain'
    U4 = 'USS suspicious'
    U5 = 'USS malig'


@enum.unique
class SideOpinion(enum.Enum):
    """Side-specific opinion"""
    OB = 'Benign'
    OM = 'Malignant'
    ON = 'Normal'
    OS = 'Suspicious'
    OU = 'Uncertain'


@enum.unique
class Event(enum.Enum):
    """Type of event. Corresponds to the fields of :class:`omidb.events.Events`"""
    assessment = 'assessment'
    biopsy_fine = 'biopsy_fine'
    biopsy_wide = 'biopsy_wide'
    clinical = 'clinical'
    screening = 'screening'
    surgery = 'surgery'


@dataclass
class BaseEvent:
    """
    Generic NBSS information pertaining to a medical procedure.

    :param left_opinion: Code summarising the diagnosis of the left breast
    :param right_opinion: Code summarising the diagnosis of the right breast
    :param dates: Dates extracted from left and right lesion data
    """
    left_opinion: Optional[SideOpinion] = None
    right_opinion: Optional[SideOpinion] = None
    dates: Optional[List[datetime.date]] = None


@dataclass
class BreastScreeningData:
    """
    Side-specific breast-screening data.

    :param date: Date that the examination took place
    :param equipment_make_model: Short description of the equipment used for
        the examination. Typically the manufacturer of the imaging device.
    :param opinion: Enumeration representing the opinion code
    """
    date: Optional[datetime.date] = None
    equipment_make_model: Optional[str] = None
    opinion: Optional[Opinion] = None


@dataclass
class Screening(BaseEvent):
    """
    NBSS information pertaining to a screening procedure.

    :param left: Screening information for the left breast
    :param right: Screening information for the right breast
    """
    left: Optional[BreastScreeningData] = None
    right: Optional[BreastScreeningData] = None


@dataclass
class Events:
    """
    A collection of events, for a given :class:`omidb.core.Episode`.
    """
    screening: Optional[Screening] = None
    assessment: Optional[BaseEvent] = None
    clinical: Optional[BaseEvent] = None
    biopsy_wide: Optional[BaseEvent] = None
    biopsy_fine: Optional[BaseEvent] = None
    surgery: Optional[BaseEvent] = None
