import pandas as pd
from qgis.PyQt.QtCore import QObject, QVariant, pyqtSignal


class SyncInspectorRowWorker(QObject):
    """
    Worker to get row ids matching with inspector line positions.
    Must be called inside QThread
    """

    finished = pyqtSignal()

    def __init__(self, parent, plugin):
        super().__init__(parent)
        self.plugin = plugin
        self.result = {}

    def run(self):

        try:
            self.get_row_ids()
        except Exception:
            pass

    def get_row_ids(self) -> None:
        """
        Return a dict of assay layers with row ids to select.
        """
        result = {}

        def replace_qvariant(value):
            if isinstance(value, QVariant):
                return None
            else:
                return value

        # get positions
        depth_positions = {}
        for config in self.plugin.depth_assay_visu_widget._visualization_config.list:
            for col_name, col_config in config.column_config.items():
                if col_config.plot_widget:
                    assay_name = col_config.assay_name
                    hole_id = col_config.hole_id
                    inspector = col_config.plot_widget.inspector
                    # get drilled length (work for altitude or length mode)
                    position = inspector._get_trace_coordinates(inspector.pos().y())[3]
                    if depth_positions.get(assay_name) is None:
                        depth_positions[assay_name] = {}

                    if depth_positions.get(assay_name).get(hole_id) is None:
                        depth_positions[assay_name][hole_id] = [position]
                    else:
                        depth_positions[assay_name][hole_id].append(position)

        time_positions = {}
        for config in self.plugin.time_assay_visu_widget._visualization_config.list:
            for col_name, col_config in config.column_config.items():
                if col_config.plot_widget:
                    assay_name = col_config.assay_name
                    hole_id = col_config.hole_id
                    inspector = col_config.plot_widget.inspector
                    if time_positions.get(assay_name) is None:
                        time_positions[assay_name] = {}

                    if time_positions.get(assay_name).get(hole_id) is None:
                        time_positions[assay_name][hole_id] = [inspector.pos().x()]
                    else:
                        time_positions[assay_name][hole_id].append(inspector.pos().x())

        # select rows for depth viewer
        for assay, hole_dict in depth_positions.items():
            # get layer
            lyr = [
                layer
                for layer in self.plugin.assay_layers
                if assay.lower() == layer.name().split(" - ")[0].lower()
            ][0]
            row_ids = []
            hole_column = [feature["hole"] for feature in lyr.getFeatures()]

            try:
                field = "depth"
                depth_column = [feature[field] for feature in lyr.getFeatures()]
            except:
                field = "top"
                depth_column = [feature[field] for feature in lyr.getFeatures()]

            # make dataframe
            df = pd.DataFrame({"hole": hole_column, "depth": depth_column})
            df = df.applymap(replace_qvariant)
            df["depth"] = df["depth"].astype(float)
            df["index"] = df.index
            row_ids = []
            for hole, positions in hole_dict.items():
                sub_df = df[df["hole"] == hole]
                for pos in positions:
                    try:
                        index = sub_df.loc[
                            (sub_df["depth"] - pos).abs().idxmin(), "index"
                        ]
                        row_ids.append(index + 1)
                    except:
                        continue

            result[lyr] = row_ids

        # select rows for time viewer
        for assay, hole_dict in time_positions.items():
            # get layer
            lyr = [
                layer
                for layer in self.plugin.assay_layers
                if assay == layer.name().split(" - ")[0]
            ][0]
            row_ids = []
            hole_column = [feature["hole"] for feature in lyr.getFeatures()]
            depth_column = [feature["x"] for feature in lyr.getFeatures()]
            # transform to unix time
            depth_column = [time.toMSecsSinceEpoch() / 1000 for time in depth_column]

            # make dataframe
            df = pd.DataFrame({"hole": hole_column, "time": depth_column})
            df = df.applymap(replace_qvariant)
            df["time"] = df["time"].astype(float)
            df["index"] = df.index
            row_ids = []
            for hole, positions in hole_dict.items():
                sub_df = df[df["hole"] == hole]
                for pos in positions:
                    try:
                        index = sub_df.loc[
                            (sub_df["time"] - pos).abs().idxmin(), "index"
                        ]
                        row_ids.append(index + 1)
                    except:
                        continue

            result[lyr] = row_ids
        self.result = result
        self.finished.emit()
