from xplordb.datamodel.collar import Collar
from xplordb.datamodel.dataset import Dataset
from xplordb.datamodel.lith import Lith
from xplordb.datamodel.metadata import RawCollarMetadata
from xplordb.datamodel.person import Person
from xplordb.datamodel.survey import Survey
from xplordb.import_data import ImportData

from openlog.datamodel.connection.interfaces.read_interface import ReadInterface
from openlog.datamodel.connection.interfaces.write_interface import WriteInterface


class XplordbWriteInterface(WriteInterface):
    def __init__(self, session, read_iface: ReadInterface):
        """
        Implement WriteInterface with a xplordb session

        Args:
            session: sqlalchemy session created from engine
        """
        super(XplordbWriteInterface, self).__init__()
        self.session = session
        self._read_iface = read_iface

    def can_import_collar(self) -> bool:
        """
        Indicate if connection can import collar

        Returns: True

        """
        return True

    def import_collar(self, collars: [Collar]) -> None:
        """
        Import collar into xplordb database.

        Raises WriteInterface.ImportException on import failure

        Args:
            collars: collars to be imported
        """
        try:
            import_data = ImportData(self.session)
            import_data.import_collars_array(collars)
        except ImportData.ImportException as exc:
            self.session.rollback()
            raise WriteInterface.ImportException(exc)

    def import_collar_metadata(self, metadatas: [RawCollarMetadata]) -> None:
        """
        Import collar into xplordb database.

        Raises WriteInterface.ImportException on import failure

        Args:
            collars: collars to be imported
        """
        try:
            import_data = ImportData(self.session)
            import_data.import_metadatas_array(metadatas)
        except ImportData.ImportException as exc:
            self.session.rollback()
            raise WriteInterface.ImportException(exc)

    def import_datasets(self, datasets: [Dataset]) -> None:
        """
        Import dataset into xplordb database.

        Raises WriteInterface.ImportException on import failure

        Args:
            datasets: datasets to be imported
        """
        try:
            import_data = ImportData(self.session)
            import_data.import_datasets_array(datasets)
        except ImportData.ImportException as exc:
            self.session.rollback()
            raise WriteInterface.ImportException(exc)

    def person_code_max_size(self) -> int:
        """
        Define maximum size for person code creation

        Returns: 3

        """
        return 3

    def import_persons(self, persons: [Person]) -> None:
        """
        Import persons into xplordb database.

        Raises WriteInterface.ImportException on import failure

        Args:
            persons: persons to be imported
        """
        try:
            import_data = ImportData(self.session)
            import_data.import_persons_array(persons)
        except ImportData.ImportException as exc:
            self.session.rollback()
            raise WriteInterface.ImportException(exc)

    def import_surveys(self, surveys: [Survey]) -> None:
        """
        Import survey into xplordb database.

        Raises WriteInterface.ImportException on import failure

        Args:
            surveys: surveys to be imported
        """

        try:
            import_data = ImportData(self.session)
            import_data.import_surveys_array(surveys)
        except ImportData.ImportException as exc:
            self.session.rollback()
            raise WriteInterface.ImportException(exc)

    def selected_collar_survey_definition_available(self) -> bool:
        """
        Return True if the collar survey definition is available
        :return: A boolean value.
        """
        return True

    def selected_collar_edition_available(self):

        return True

    def replace_collar_surveys(self, collar_id: str, surveys: [Survey]) -> None:
        """
        Replace survey for collar

        Args:
            collar_id:: The collar id of the hole
            surveys: new survey for collar
        """
        current_survey = self._read_iface.get_surveys_from_collars([collar_id])
        for survey in current_survey:
            self.session.delete(survey)
        self.session.flush()
        self.import_surveys(surveys)

    def replace_collar_planned_surveys(self, collar_id: str, survey: Survey) -> None:

        """
        Replace planned survey for collar

        Args:
            collar_id:: The collar id of the hole
            survey: new planned survey for collar
        """
        collar = self._read_iface.get_collar(collar_id)
        collar.dip = survey.dip
        collar.azimuth = survey.azimuth
        collar.planned_eoh = survey.depth
        self.session.commit()

    def update_collars(self, collar_list) -> None:
        """
        Update collars from database.
        Args:
            - collar_list : list of collars to update
        """
        try:
            for collar in collar_list:
                db_collar = self._read_iface.get_collar(hole_id=collar.hole_id)
                db_collar.x = (collar.x,)
                db_collar.y = collar.y
                db_collar.z = (collar.z,)
                db_collar.planned_x = (collar.planned_x,)
                db_collar.planned_y = (collar.planned_y,)
                db_collar.planned_z = (collar.planned_z,)
                db_collar.eoh = (collar.eoh,)
                db_collar.planned_eoh = (collar.planned_eoh,)
                db_collar.srid = (collar.srid,)

            self.session.commit()

        except Exception as exc:
            self.session.rollback()
            raise WriteInterface.ImportException(exc)

    def remove_collars(self, collar_ids):
        """
        Remove collar from database by its ID.
        """
        try:
            for collar_id in collar_ids:
                # first, delete surveys
                self.session.execute(
                    f"DELETE FROM dh.surv WHERE hole_id = '{collar_id}';"
                )

                # delete metadatas
                self.session.execute(
                    f"DELETE FROM dh.metadata WHERE hole_id = '{collar_id}';"
                )

                collar = self._read_iface.get_collar(collar_id)
                self.session.delete(collar)

            self.session.commit()
            return True
        except Exception as exc:
            self.session.rollback()
            return False
