import typing
from pathlib import Path

from . import PyMesh, PyNCMeshGeometry, PyNCMeshDataExtractor, QgisMeshGeometry, QgisDataExtractor
from .mesh3d import Mesh3DMixin, GLTFMixin


class PyNCMesh(PyMesh, Mesh3DMixin, GLTFMixin):

    def __init__(self, fpath: str | Path, geom_driver: str = None, engine: str = None, mesh: typing.Any = None):
        super().__init__()
        self.fpath = Path(fpath)

        if not geom_driver and engine == 'qgis':
            geom_driver = 'qgis'
        elif not geom_driver and not engine:
            if not self.pv_available() and not self.qgis_available():
                raise ValueError('Neither PyVista nor QGIS python bindings were found.')

        if (geom_driver and geom_driver.lower() == 'qgis') or (geom_driver is None and not self.pv_available()):
            if not self.qgis_available():
                raise ValueError("QGIS python bindings not found.")
            if not self.qgis_initialized():
                raise ValueError('QGIS application has not been initialized.')
            self.geom = QgisMeshGeometry(fpath)
            if mesh is not None:
                self.geom.lyr = mesh
        else:
            self.geom = PyNCMeshGeometry(fpath)

        if engine == 'qgis' or (engine is None and not self.external_engine_available() and self.qgis_available()):
            if not self.qgis_available():
                raise ValueError("QGIS python bindings not found.")
            if not self.qgis_initialized():
                raise ValueError('QGIS application has not been initialized.')
            self.extractor = QgisDataExtractor(fpath, extra_datasets=[], layer=self.geom.lyr)
            self.geom.lyr = self.extractor.lyr
        elif self.external_engine_available():
            self.extractor = PyNCMeshDataExtractor(fpath, engine)
        else:
            raise ValueError('No suitable engine found for data extraction.')

        self.geom.spherical = self.extractor.spherical()
        self.name = self.fpath.stem
        with self.extractor.open():
            for dtype in self.data_types():
                if dtype.lower() != 'bed elevation':
                    ref_time = self.reference_time_(dtype)
                    if ref_time is not None:
                        self.has_inherent_reference_time = True
                        self.reference_time = ref_time
                    break

    def translate_data_type(self, data_type: str) -> tuple[str, ...]:
        data_type = super().translate_data_type(data_type)
        if isinstance(self.extractor, PyNCMeshDataExtractor):
            data_type = tuple([self.extractor.long_name_to_variable.get(x, x) for x in data_type])
        if self.extractor.NAME == 'QgisDataExtractor':
            return data_type
        if len(data_type) == 1 and self.extractor.is_vector(data_type[0]) and f'{data_type[0]}_x' in self.extractor.long_name_to_variable.values():
            return f'{data_type[0]}_x', f'{data_type[0]}_y'
        return data_type
