#    Copyright 2022 SECTRA AB
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

from pathlib import Path
from typing import Dict, Optional, Tuple, Union

from tifffile.tifffile import (
    PHOTOMETRIC,
    FileHandle,
    TiffFile,
    TiffPage,
    TiffPageSeries,
)

from opentile.common import NativeTiledPage, Tiler
from opentile.geometry import Size, SizeMm
from opentile.jpeg import Jpeg
from opentile.metadata import Metadata


class HistechTiffTiledPage(NativeTiledPage):
    def __init__(self, page: TiffPage, fh: FileHandle, base_shape: Size):
        """OpenTiledPage for 3DHistech Tiff-page.

        Parameters
        ----------
        page: TiffPage
            TiffPage defining the page.
        fh: FileHandler
            Filehandler to read data from.
        base_shape: Size
            Size of base level in pyramid.
        """
        super().__init__(page, fh)
        self._base_shape = base_shape
        self._pyramid_index = self._calculate_pyramidal_index(self._base_shape)
        self._mpp = self._get_mpp_from_page()

    def __repr__(self) -> str:
        return (
            f"{type(self).__name__}({self._page}, {self._fh}, " f"{self._base_shape})"
        )

    @property
    def pixel_spacing(self) -> SizeMm:
        """Return pixel spacing in mm per pixel."""
        return self.mpp * 1000

    @property
    def mpp(self) -> SizeMm:
        """Return pixel spacing in um per pixel."""
        return self._mpp

    @property
    def photometric_interpretation(self) -> PHOTOMETRIC:
        photometric_interpretation = PHOTOMETRIC(self._page.photometric)
        if photometric_interpretation == PHOTOMETRIC.PALETTE:
            return PHOTOMETRIC.MINISBLACK
        return photometric_interpretation

    def _get_mpp_from_page(self) -> SizeMm:
        items_split = self._page.description.split("|")
        header = items_split.pop(0)
        items = {
            key: value
            for (key, value) in (item.split(" = ", 1) for item in items_split)
        }
        return (
            SizeMm(float(items["3dh_PixelSizeX"]), float(items["3dh_PixelSizeY"]))
            / 1000
            / 1000
        )


class HistechTiffTiler(Tiler):
    def __init__(
        self, filepath: Union[str, Path], turbo_path: Optional[Union[str, Path]] = None
    ):
        """Tiler for 3DHistech tiff file.

        Parameters
        ----------
        filepath: Union[str, Path]
            Filepath to a 3DHistech-TiffFile.
        """
        super().__init__(Path(filepath))
        self._fh = self._tiff_file.filehandle

        self._turbo_path = turbo_path
        self._jpeg = Jpeg(self._turbo_path)

        self._level_series_index = 0
        for series_index, series in enumerate(self.series):
            if self.is_label(series):
                self._label_series_index = series_index
            elif self.is_overview(series):
                self._overview_series_index = series_index
        self._pages: Dict[Tuple[int, int, int], HistechTiffTiledPage] = {}

    @property
    def metadata(self) -> Metadata:
        """No known metadata for 3DHistech tiff files."""
        return Metadata()

    @classmethod
    def supported(cls, tiff_file: TiffFile) -> bool:
        return "3dh_PixelSizeX" in tiff_file.pages.first.description

    def get_page(self, series: int, level: int, page: int = 0) -> HistechTiffTiledPage:
        """Return PhilipsTiffTiledPage for series, level, page."""
        if not (series, level, page) in self._pages:
            self._pages[series, level, page] = HistechTiffTiledPage(
                self._get_tiff_page(series, level, page), self._fh, self.base_size
            )
        return self._pages[series, level, page]

    @staticmethod
    def is_overview(series: TiffPageSeries) -> bool:
        """Return true if series is a overview series."""
        return False

    @staticmethod
    def is_label(series: TiffPageSeries) -> bool:
        """Return true if series is a label series."""
        return False
