from dataclasses import dataclass
from typing import List
from typing import NamedTuple
from typing import Optional

from ...io.hdf5 import join_h5url
from ..pymca_config import PyMcaXrfConfiguration


class FitUris(NamedTuple):
    bliss_scan_uris: List[str]
    detector_name: str
    output_root_uri: str
    xrf_spectra_uri_template: str = "instrument/{}/data"
    energy_uri_template: str = "instrument/positioners/{}"
    energy_name: Optional[str] = None
    process_uri_template: str = "fit/{}"

    @property
    def xrf_spectra_uris(self) -> List[str]:
        template = self.xrf_spectra_uri_template
        return [
            f"{bliss_scan_uri}/{template.format(self.detector_name)}"
            for bliss_scan_uri in self.bliss_scan_uris
        ]

    @property
    def output_parent_uri(self) -> str:
        output_uri_template = join_h5url(
            self.output_root_uri, self.process_uri_template
        )
        return output_uri_template.format(self.detector_name)

    @property
    def beam_energy_uris(self) -> List[Optional[str]]:
        if not self.energy_name:
            return [None] * len(self.bliss_scan_uris)
        template = self.energy_uri_template
        return [
            f"{bliss_scan_uri}/{template.format(self.energy_name)}"
            for bliss_scan_uri in self.bliss_scan_uris
        ]


@dataclass
class ProgressStats:
    seconds_read: float = 0.0
    seconds_process: float = 0.0
    seconds_write: float = 0.0


class FitTask(NamedTuple):
    xrf_spectra_uri: str
    beam_energy_uri: Optional[str]
    start_in: int
    stop_in: int
    start_out: int
    stop_out: int
    output_parent_uri: str
    progress: ProgressStats

    @property
    def num_spectra(self) -> int:
        return self.stop_in - self.start_in


class FitArguments(NamedTuple):
    configuration: PyMcaXrfConfiguration
    quantification: Optional[bool]
    individual_weights: Optional[bool]
    positive_peak_areas: Optional[bool]
    energy_multiplier: Optional[bool]
    fast_fitting: Optional[bool]
    native_fitting: Optional[bool]
    native_legacy_fitting: Optional[bool]
    diagnostics: Optional[bool]
