import looker_sdk
from looker_sdk.sdk.api40.models import WriteQuery
from collections import defaultdict
import json

class LookerSDK:
    def __init__(self, property_id=None):
        self.sdk = looker_sdk.init40()
        self.property_id = property_id
         
    def getDimensionUniqueValue(self, view, dimension, date="7 days"):
        query = {
            "view": view,
            "fields": [
                f"{dimension}"
            ],
            "model": f"c360_client_{self.property_id}",
            "limit": "1000",
            "filters": {
                f"{dimension}": "-NULL",
                "event.event_time_stamp_date": date
            }
        }

        queryLooker = self.sdk.create_query(body=query)
        result = self.sdk.run_query(query_id=queryLooker.id, result_format='json')
        return json.loads(result)
    
    def getDimensionUniqueValueProperty(self, view, dimension, parent_dimension, parent_value, date="7 days"):
        query = {
            "view": view,
            "fields": [
                f"{dimension}"
            ],
            "model": f"c360_client_{self.property_id}",
            "limit": "1000",
            "filters": {
                f"{dimension}": "-NULL",
                "event.event_time_stamp_date": date,
                parent_dimension: parent_value
            }
        }

        queryLooker = self.sdk.create_query(body=query)
        result = self.sdk.run_query(query_id=queryLooker.id, result_format='json')
        return json.loads(result)
    
    def build_filter_expression(self, filters):
        """
        Convert filter definitions into Looker matches_filter expression.
        Supports between, startswith, endswith, equal, contains
        and their 'not_' variants.
        """

        def condition_to_str(cond):
            dim = f"${{{cond['dimension']}}}"
            val = cond['value']
            condition = cond['condition']

            negate = condition.startswith("not_")
            base_cond = condition[4:] if negate else condition

            def prefix(v)->str: return "-" + v if negate else v

            if base_cond == "between":
                expr = f"{prefix(val[0])} to {val[1]}"
            elif base_cond == "relative":
                expr = val[0]
            elif base_cond == "startswith":
                expr = ",".join(prefix(v.replace("_", "^_") + "%") for v in val)
            elif base_cond == "endswith":
                expr = ",".join(prefix("%" + v) for v in val)
            elif base_cond == "equal":
                expr = ",".join(prefix(v) for v in val)
            elif base_cond == "contains":
                expr = ",".join(prefix("%" + v + "%") for v in val)
            elif base_cond == "blank":
                expr = prefix("NULL")
            else:
                raise ValueError(f"Unknown condition: {condition}")

            return f"matches_filter({dim}, `{expr}`)"

        groups = []
        for group in filters:
            and_parts = []
            for cond in group:
                and_parts.append(condition_to_str(cond))
            groups.append("(" + " AND ".join(and_parts) + ")")

        return " OR ".join(groups)

    def build_audience(self, view, conditions, cache):
        expression = {
            "view": view,
            "fields": [f"{view}.list_of_user"],
            "filter_expression": conditions,
            "model": f"c360_client_{self.property_id}",
            "limit": "1",
            "can": {
                "can_clear_cache": True,
                "cost_estimate": True,
                "create": True,
                "index": True,
                "show": True,
                "download": True,
                "download_unlimited": True,
                "edit_custom_fields": True,
                "edit_table_calculations": True,
                "explore": True,
                "generate_drill_links": True,
                "render": True,
                "run": True,
                "see_results": True,
                "save": True,
                "see_aggregate_table_lookml": True,
                "see_derived_table_lookml": True,
                "see_lookml": True,
                "see_sql": True,
                "use_custom_fields": True
            }
        }

        query = self.sdk.create_query(body=expression)
        data = self.sdk.run_query(query_id=query.id, result_format='json', cache=cache, cache_only=cache)
        return json.loads(data)
    
    def createAudienceJson(self, view, filters):
        query = {
            "view": view,
            "fields": [
                "event.list_of_user"
                ],
            "filters": filters,
            "model": f"c360_client_{self.property_id}",
            "limit": "1"
        }
        return query
        # queryLooker = self.sdk.create_query(body=query)
        # result = self.sdk.run_query(query_id=queryLooker.id, result_format='json')
        # return json.loads(result)

    
    def calculateAudience(self, query):
        queryLooker = self.sdk.create_query(body=query)
        result = self.sdk.run_query(query_id=queryLooker.id, result_format='json')
        return json.loads(result)
    

    def download_audience_profile(self, audience_ids, limit:int = 500):
        query = {
            "model": f"c360_client_{self.property_id}",
            "view": "profile_explore",
            "fields": [
                "profile_explore.lastupdate_time",
                "profile_explore.user_pseudo_id",
                "profile_explore__user_property.facebook",
                "profile_explore__user_property.line",
                "profile_explore__user_property.phonenumber",
                "profile_explore__user_property.email"
            ],
            "filters": {
                "profile_explore.user_pseudo_id": ",".join(audience_ids)
            },
            "sorts": [
                "profile_explore.lastupdate_time desc"
            ],
            "limit": limit
        }
        print(query)
        queryLooker = self.sdk.create_query(body=query)
        result = self.sdk.run_query(query_id=queryLooker.id, result_format='json')
        return json.loads(result)
