<gh_stars>0
from .base import MetricsLayerBase
from .join import Join
from .set import Set


class Explore(MetricsLayerBase):
    def __init__(self, definition: dict = {}, project=None) -> None:
        if definition.get("from") is not None:
            definition["from_"] = definition["from"]
        elif definition.get("view_name") is not None:
            definition["from_"] = definition["view_name"]
        else:
            definition["from_"] = definition["name"]

        self.project = project
        self._view_names = []
        self.validate(definition)
        super().__init__(definition)

    @property
    def week_start_day(self):
        if self.model.week_start_day:
            return self.model.week_start_day.lower()
        return "monday"

    def validate(self, definition: dict):
        required_keys = ["name", "model", "from_"]
        for k in required_keys:
            if k not in definition:
                raise ValueError(f"Explore missing required key {k}")

    def printable_attributes(self):
        to_print = ["name", "type", "from", "label", "group_label", "model_name", "join_names"]
        attributes = self.to_dict()
        attributes["type"] = "explore"
        attributes["from"] = attributes["from_"]
        attributes["join_names"] = [j["name"] for j in attributes.get("joins", [])]
        return {key: attributes.get(key) for key in to_print if attributes.get(key) is not None}

    def validate_fields(self):
        errors = []
        for view_name in self.view_names():
            view = self.project.get_view(view_name)
            if view is None:
                print(f"ERROR: View {view_name} cannot be found in explore {self.name}")
                continue
            referenced_fields = view.referenced_fields()
            view_errors = view.collect_errors()

            errors.extend(
                [
                    f"Could not locate reference {field} in view {view_name} in explore {self.name}"
                    for field in referenced_fields
                    if isinstance(field, str)
                ]
            )
            errors.extend(view_errors)

        return list(sorted(list(set(errors))))

    def view_names(self):
        if self._view_names:
            return self._view_names
        self._view_names = [self.from_] + [j.from_ for j in self.joins()]
        return self._view_names

    def join_names(self):
        return [self.name] + [j["name"] for j in self._definition.get("joins", [])]

    def field_names(self):
        # This function is for the explore `fields` parameter, to resolve all the sets into field names
        if self.fields is None:
            return self.fields

        set_definition = {"name": "NA", "fields": self.fields, "explore_name": self.name}
        explore_set = Set(set_definition, project=self.project, explore=self)
        return explore_set.field_names()

    def get_join(self, join_name: str, by_view_name: bool = False):
        if by_view_name:
            return next((j for j in self.joins() if j.from_ == join_name), None)
        return next((j for j in self.joins() if j.name == join_name), None)

    def joins(self):
        output = []
        for j in self._definition.get("joins", []):
            join = Join(j, explore=self, project=self.project)
            if join.is_valid():
                output.append(join)
        return output

from .base import MetricsLayerBase
from .join import Join
from .set import Set


class Explore(MetricsLayerBase):
    def __init__(self, definition: dict = {}, project=None) -> None:
        if definition.get("from") is not None:
            definition["from_"] = definition["from"]
        elif definition.get("view_name") is not None:
            definition["from_"] = definition["view_name"]
        else:
            definition["from_"] = definition["name"]

        self.project = project
        self._view_names = []
        self.validate(definition)
        super().__init__(definition)

    @property
    def week_start_day(self):
        if self.model.week_start_day:
            return self.model.week_start_day.lower()
        return "monday"

    def validate(self, definition: dict):
        required_keys = ["name", "model", "from_"]
        for k in required_keys:
            if k not in definition:
                raise ValueError(f"Explore missing required key {k}")

    def printable_attributes(self):
        to_print = ["name", "type", "from", "label", "group_label", "model_name", "join_names"]
        attributes = self.to_dict()
        attributes["type"] = "explore"
        attributes["from"] = attributes["from_"]
        attributes["join_names"] = [j["name"] for j in attributes.get("joins", [])]
        return {key: attributes.get(key) for key in to_print if attributes.get(key) is not None}

    def validate_fields(self):
        errors = []
        for view_name in self.view_names():
            view = self.project.get_view(view_name)
            if view is None:
                print(f"ERROR: View {view_name} cannot be found in explore {self.name}")
                continue
            referenced_fields = view.referenced_fields()
            view_errors = view.collect_errors()

            errors.extend(
                [
                    f"Could not locate reference {field} in view {view_name} in explore {self.name}"
                    for field in referenced_fields
                    if isinstance(field, str)
                ]
            )
            errors.extend(view_errors)

        return list(sorted(list(set(errors))))

    def view_names(self):
        if self._view_names:
            return self._view_names
        self._view_names = [self.from_] + [j.from_ for j in self.joins()]
        return self._view_names

    def join_names(self):
        return [self.name] + [j["name"] for j in self._definition.get("joins", [])]

    def field_names(self):
        # This function is for the explore `fields` parameter, to resolve all the sets into field names
        if self.fields is None:
            return self.fields

        set_definition = {"name": "NA", "fields": self.fields, "explore_name": self.name}
        explore_set = Set(set_definition, project=self.project, explore=self)
        return explore_set.field_names()

    def get_join(self, join_name: str, by_view_name: bool = False):
        if by_view_name:
            return next((j for j in self.joins() if j.from_ == join_name), None)
        return next((j for j in self.joins() if j.name == join_name), None)

    def joins(self):
        output = []
        for j in self._definition.get("joins", []):
            join = Join(j, explore=self, project=self.project)
            if join.is_valid():
                output.append(join)
        return output
# This function is for the explore `fields` parameter, to resolve all the sets into field names