from flask import Blueprint, request
import logging
from datetime import datetime
from firebase.firebase import Firebase
import pytz 
import utility.function as func
import os
import uuid
from bigquery.bq import BigQuery
from feature.audience.craft import BQCraft
from utility.jsonschemaValidate import *
from feature.audience.queryBuilder import *
from feature.audience.node import *
from feature.audience.audience_builder import AudinceBuilder
logging.basicConfig(level=logging.INFO)

evntFunction = func.Event()
feature_audience_builder = Blueprint('feature_audience_builder', __name__, url_prefix='/feature/audience/builder')

fb = Firebase(host=os.environ.get("FIREBASE_HOST"))
timezone = pytz.timezone('Asia/Bangkok')

@feature_audience_builder.route('/suggestion',  methods=['GET'])
@feature_audience_builder.route('/suggestion/',  methods=['GET'])
def feature_audience_builder_suggestion():
    try:
        if request.method == 'GET':
            data = request.args
            for req in ['property_id', 'source']:
                if req not in data:
                    return {'message': f"{req} is required"}, 400
            
            property_id = data.get("property_id", None)
            source = data.get("source", None)

            if source not in ['event', 'user', 'ad_refferal']:
                return {'status': 'error', 'message': f'source must be all, event, user, ad_refferal or ga4'}, 400

            if source == 'all':
                suggestionData = fb.db.reference().child(f"account/{property_id}/cache/suggestion").get()
                return {'status': 'ok', 'data': suggestionData} if suggestionData else {'status': 'not fond', 'message': f"Property {property_id} has no suggestion value yet"}, 400
            else:
                suggestionData = fb.db.reference().child(f"account/{property_id}/cache/suggestion/{source}").get()
                return {'status': 'ok', 'data': suggestionData} if suggestionData else {'status': 'not fond', 'message': f"Property {property_id} has no suggestion value for {source}"}, 400
        return {'status': 'error', 'message': 'Method not allowed'}, 405
    except Exception as e:
        logging.error(e)
        return {"status": "error", "message": e}, 500

@feature_audience_builder.route('/',  methods=['POST','GET', 'PUT', "DELETE"])
@feature_audience_builder.route('',  methods=['POST','GET', 'PUT', "DELETE"])
def feature_audience_builder_func():
    timestampNow = datetime.now().timestamp()
    try:
        if request.method == 'POST':
            data = request.get_json()
            for req in ['property_id', 'user_id','name', 'json']:
                if req not in data:
                    return {'message': f"{req} is required"}, 400
            
            now = datetime.now(timezone)
            time = now.strftime('%Y-%m-%d %H:%M:%S')
            property_id = data.get('property_id')
            json = data.get('json')
            name = data.get('name')
            user_id = data.get('user_id', '-')
            jsonFormated = audienceJson(json)
            
            #Validate json
            if jsonFormated['status'] != 'ok':
                return jsonFormated, 500
            
            audience_id = str(uuid.uuid4())
            audiences_audience_log_json = BQCraft.audiences_audience_log_json_builder(user_id, "CREATE", json, int(timestampNow))
            
            #Save to Firbase
            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/audience_id").set(audience_id)
            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/json").set(json)
            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/active").set(False)
            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/name").set(name)
            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/createdate").set(time)
            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/lastupdate").set(time)
            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/audience_log").set([audiences_audience_log_json])
            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/type").set("builder")
            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/channel").set("all")
            
            return {'status': 'ok', 'audience_id': audience_id}, 200
        
        elif request.method == 'GET':
            data = request.args
            for req in ['property_id', 'audience_id']:
                if req not in data:
                    return {"status":"error",'message': f"{req} is require"}, 400
            
            property_id = data.get('property_id')
            audience_id = data.get('audience_id')
            if audience_id != 'all':
                audience_context = fb.db.reference().child(f"account/{property_id}/audience/{audience_id}").get()
                returnAudience = [audience_context]
            else:
                audience_context = fb.db.reference().child(f"account/{property_id}/audience").get()
                if audience_context:
                    returnAudience = []
                    for a in audience_context:
                        au = audience_context[a]
                        returnAudience.append(au)
                else:
                    return {'status': 'not fond', 'message': f'This propery has no any audience'}, 400
            
            return {'status': 'ok', 'data': returnAudience}, 200
        
        elif request.method == 'DELETE':
            data = request.get_json()
            for req in ['property_id', 'audience_id']:
                if req not in data:
                    return {'message': f"{req} is required"}, 400
            
            property_id = data.get('property_id')
            audience_id = data.get('audience_id')
            
            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}").delete()
            return {'status': 'ok', 'message': f"Audience ID {audience_id} was deleted"}, 200
        
        elif request.method == 'PUT':
            data = request.get_json()
            for req in ['property_id', 'user_id','audience_id', 'json']:
                if req not in data:
                    return {'message': f"{req} is required"}, 400
            
            property_id = data.get('property_id')
            audience_id = data.get('audience_id')
            json = data.get('json')
            user_id = data.get("user_id", '-')
            name = data.get('name', None)

            jsonFormated = audienceJson(json)

            #Validate json
            if jsonFormated['status'] != 'ok':
                return jsonFormated, 500
            
            # Check automation_id exist
            audienceContext = fb.db.reference().child(f"account/{property_id}/audience/{audience_id}").get(shallow=True)
            if not audienceContext:
                return {'status': 'not found', 'message': f"Audience ID: {audience_id} not fond"}, 400
            
            audience_log = fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/audience_log").get()
            audiences_audience_log_json = BQCraft.audiences_audience_log_json_builder(user_id, "CHANGE", json, int(timestampNow))
            audience_log.append(audiences_audience_log_json)
            
            now = datetime.now(timezone)
            time = now.strftime('%Y-%m-%d %H:%M:%S')
            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/lastupdate").set(time)
            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/json").set(json)
            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/audience_log").set(audience_log)
            
            if name:
                fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/name").set(name)

            return {'status': 'ok', 'message': f"Audience ID {audience_id} was updated"}, 200

        return {'status': 'error', 'message': 'Method not allowed'}, 405
    except Exception as e:
        logging.error(e)
        return {"status": "error", "message": e}, 500

@feature_audience_builder.route('/execute',  methods=['POST','GET', 'PUT', "DELETE"])
@feature_audience_builder.route('/execute/',  methods=['POST','GET', 'PUT', "DELETE"])
def feature_audience_builder_execute():
    try:
        data = request.get_json()
        for req in ['property_id', 'audience_id']:
            if req not in data:
                return {'message': f"{req} is require"}, 400
        
        property_id = data.get('property_id')
        audience_id = data.get('audience_id')
        
        audience = fb.db.reference().child(f"account/{property_id}/audience/{audience_id}").get()
        if not audience:
            return {'status': 'not found', 'message': f"Automation ID: {audience_id} not fond"}, 400
        
        audienceJson = audience['json']

        for node in audienceJson['nodes']:
            if node['type'] == 'query':
                query = QueryGenerator(property_id, node['query']).generate()
                node['query'] = query
        
        bq = BigQuery()
        au = AudienceBuilder(property_id, audience_id, audienceJson, bq)
        result = au.execute()

        return {'status': 'ok', 'data': result}, 200

    except Exception as e:
        logging.error(e)
        return {"status": "error", "message": e}, 500

@feature_audience_builder.route('/status',  methods=['POST'])
def feature_audience_builder_status():
    try:
        if request.method == 'POST':
            data = request.get_json()
            for req in ['property_id', 'user_id', 'audience_id', 'status']:
                if req not in data:
                    return {'message': f"{req} is require"}, 400

            property_id = data.get("property_id", None)
            user_id = data.get("user_id", "No user")
            audience_id = data.get("audience_id", None)
            status = data.get("status", None)
            try:
                status = bool(status)
            except ValueError:
                return {'message': f'''status value must be boolean type'''}, 400
            
            #Check audience exist
            audienceExist = fb.db.reference().child(f"account/{property_id}/audience/{audience_id}").get(shallow=True)
            if not audienceExist:
                return {'status': 'not fond', 'message': f'Audience Id {audience_id} not fond'},400

            fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/active").set(status)
            
            if status == True:
                #Set path audience_active_index
                listActiveAudience = fb.db.reference().child(f"account/{property_id}/audience_active_index").get()
                if not listActiveAudience:
                    listActiveAudience = []
            
                listActiveAudience.append(audience_id)
                fb.db.reference().child(f"account/{property_id}/audience_active_index").set(list(set(listActiveAudience)))
            else:
                #Remove path audience_active_index
                listActiveAudience = fb.db.reference().child(f"account/{property_id}/audience_active_index").get()
                if listActiveAudience:
                    if audience_id in listActiveAudience:
                        listActiveAudience.remove(audience_id)
                        fb.db.reference().child(f"account/{property_id}/audience_active_index").set(list(set(listActiveAudience)))

            return {'status': 'ok', 'message': f'Change status audience {audience_id} has been change status to {"Active" if status == True else "Inactive" }'},200

        return {'status': 'error', 'message': 'Method not allowed'}, 405
    except Exception as e:
        logging.error(e)
        return {"status": "error", "message": e}, 500

@feature_audience_builder.route('/v2/suggestion/dimension',  methods=['GET'])
def feature_audience_builder_suggestion_dimension():
    try:
        if request.method == 'GET':
            data = request.args
            for req in ['property_id', 'source']:
                if req not in data:
                    return {"status":"error",'message': f"{req} is require"}, 400
            
            property_id = data.get("property_id")
            source = data.get("source")
            if source not in ['event', 'ads', 'user', 'ga4', 'offline', 'message']:
                return {'status': 'not_support', 'message': f'Not support {source}'}, 400

            from feature.audience.craft import LookerDimension
            
            data = LookerDimension.getSuggestion(source)
            logging.info('Looker Data /v2/suggestion/dimension', data)
            return {'status': 'ok', 'data': data}, 200
    
    except Exception as e:
        logging.error(e)
        return {'status': 'error', 'message': str(e)}, 500

@feature_audience_builder.route('/v2/suggestion/property',  methods=['GET'])
def feature_audience_builder_suggestion_property():
    try:
        if request.method == 'GET':
            data = request.args
            for req in ['property_id', 'source', 'dimension', 'date']:
                if req not in data:
                    return {"status":"error",'message': f"{req} is require"}, 400
            
            property_id = data.get("property_id")
            source = data.get("source")
            dimension = data.get("dimension")
            datefilter = data.get("date", "7 days")

            from utility.lookerSDK import LookerSDK
            looker = LookerSDK(property_id=property_id)
            data = looker.getDimensionUniqueValue(source, dimension, datefilter)
            logging.info('Looker Data /v2/suggestion/property')

            if data:
                return {'status': 'ok', 'data': data}, 200
            else:
                return {'status': 'not_fond', 'message': f'No value in {dimension}'}, 404
        
        return {'status': 'error', 'message': 'Method not allowed'}, 405
    except Exception as e:
        logging.error(e)
        return {'status': 'error', 'message': str(e)}, 500

@feature_audience_builder.route('/v2/suggestion/property/value',  methods=['GET'])
def feature_audience_builder_suggestion_property_value():
    try:
        if request.method == 'GET':
            data = request.args
            for req in ['property_id', 'source', 'dimension', 'date', 'parent_dimension', 'parent_value']:
                if req not in data:
                    return {"status":"error",'message': f"{req} is require"}, 400
            
            property_id = data.get("property_id")
            source = data.get("source")
            dimension = data.get("dimension")
            datefilter = data.get("date", "7 days")
            parent_dimension = data.get("parent_dimension")
            parent_value = data.get("parent_value")

            from utility.lookerSDK import LookerSDK
            looker = LookerSDK(property_id=property_id)
            data = looker.getDimensionUniqueValueProperty(source, dimension, parent_dimension, parent_value, datefilter)
            logging.info('Looker Data /v2/suggestion/property/value')
            
            if data:
                return {'status': 'ok', 'data': data}, 200
            else:
                return {'status': 'not_fond', 'message': f'No value in {dimension}'}, 404
        
        return {'status': 'error', 'message': 'Method not allowed'}, 405
    except Exception as e:
        logging.error(e)
        return {'status': 'error', 'message': str(e)}, 500

@feature_audience_builder.route('/v2',  methods=['GET', 'PUT','POST'])
@feature_audience_builder.route('/v2/',  methods=['GET', 'PUT','POST'])
def feature_audience_builder_v2():
    try:
        if request.method == 'POST':
            data = request.get_json()
            #Validate
            builder = AudinceBuilder(json=data, cache=False)
            valid, message = builder._validate_json_data()
            if not valid:
                return {'status': 'error', 'message': message}, 500
            
            now = datetime.now(timezone)
            time = now.strftime('%Y-%m-%d %H:%M:%S')
            
            property_id = data.get('property_id')
            audience_id = data.get('id')

            #Save to Friesbase
            fb.db.reference().child(f'account/{property_id}/audience/{audience_id}').set(data)
            fb.db.reference().child(f'account/{property_id}/audience/{audience_id}/active').set(False)
            fb.db.reference().child(f'account/{property_id}/audience/{audience_id}/createdate').set(time)
            fb.db.reference().child(f'account/{property_id}/audience/{audience_id}/lastupdate').set(time)
            fb.db.reference().child(f'account/{property_id}/audience/{audience_id}/total_audience').set(0)
            fb.db.reference().child(f'account/{property_id}/audience/{audience_id}/type').set("builder")

            data['createdate'] = time
            data['lastupdate'] = time
            data['total_audience'] = 0
            data['active'] = False
            
            return {'status': 'ok', 'message': f'Audience ID {audience_id} created succesfully', 'data': data},200
        
        elif request.method == 'GET':
            data = request.args
            for req in ['property_id', 'audience_id']:
                if req not in data:
                    return {"status":"error",'message': f"{req} is require"}, 400
            property_id = data.get('property_id')
            audience_id = data.get('audience_id')
            # Get audience context
            audience_context = fb.db.reference().child(f'account/{property_id}/audience/{audience_id}').get()
            if not audience_context:
                return {'status': 'not fond', 'message': 'Audience not fond'},404

            if 'nodes' not in audience_context:
                return {'status': 'ok', 'data': audience_context}, 200
            builder = AudinceBuilder(json=audience_context, cache=True)
            
            if builder.connections != {}:
                final_result = builder.get_final_audience()
            else:
                final_result = []

            popped_ids = {}

            # Iterate over the keys and values of the outer dictionary.
            if builder.audience_data:
                for key, value in builder.audience_data.items():
                    # Use .pop() to remove 'user_pseudo_ids' and store it in the new dictionary.
                    if "user_pseudo_ids" in value:
                        value.pop("user_pseudo_ids")
                        popped_ids[key] = value
                    
                audience_context['result'] = popped_ids
                return {'status': 'ok', 'data': audience_context}, 200
            else:
                return {'status': 'ok', 'data': audience_context}, 200

        elif request.method == 'PUT':
            data = request.get_json()
            builder = AudinceBuilder(json=data, cache=False)
            valid, message = builder._validate_json_data()
            if not valid:
                return {'status': 'error', 'message': message}, 500
            now = datetime.now(timezone)
            time = now.strftime('%Y-%m-%d %H:%M:%S')
            property_id = data.get('property_id')
            audience_id = data.get('id')
            # Check audience exist
            audience_exist = fb.db.reference().child(f"account/{property_id}/audience/{audience_id}").get(shallow=True)
            if not audience_exist:
                return {'status': 'error', 'message': f'No audience {audience_id} in this property'}, 500
            
            if builder.connections != {}:
                final_result = builder.get_final_audience()
            else:
                final_result = []
            fb.db.reference().child(f'account/{property_id}/audience/{audience_id}').set(data)
            fb.db.reference().child(f'account/{property_id}/audience/{audience_id}/lastupdate').set(time)
            fb.db.reference().child(f'account/{property_id}/audience/{audience_id}/total_audience').set(len(final_result))

            return {'status': 'ok', 'message': f'Audience ID {audience_id} updated succesfully'},200
        return {'status': 'error', 'message': 'Method not allowed'}, 405
    except Exception as e:
        logging.error(e)
        return {'status': 'error', 'message': str(e)}, 500
    
@feature_audience_builder.route('/v2/status',  methods=['POST'])
def feature_audience_builder_v2_status():

    try:
        if request.method == 'POST':
            data = request.get_json()
            for req in ['property_id','audience_id', 'status']:
                if req not in data:
                    return {'message': f"{req} is require"}, 400
            try:
                status = bool(data.get('status'))
            except Exception as e:
                return {'status': 'error', 'message': 'is_cache must be convert to bool'}, 500
            
            now = datetime.now(timezone)
            time = now.strftime('%Y-%m-%d %H:%M:%S')
            property_id = data.get('property_id')
            audience_id = data.get('audience_id')

            fb.db.reference().child(f'account/{property_id}/audience/{audience_id}/active').set(status)
            fb.db.reference().child(f'account/{property_id}/audience/{audience_id}/lastupdate').set(time)
            return {'status': 'ok', 'message': f"Update Audience ID {audience_id} to {'Active' if status else 'Inactive'} successfully"}, 200

        return {'status': 'error', 'message': 'Method not allowed'}, 405
    except Exception as e:
        logging.error(e)
        return {'status': 'error', 'message': str(e)}, 500

@feature_audience_builder.route('/v2/execute',  methods=['POST'])
def feature_audience_builder_data():
    try:
        if request.method == 'POST':
            data = request.get_json()

            if 'nodes' not in data:
                return {'status': 'error', 'message': 'You must provide nodes property'},500
            
            property_id = data.get("property_id")
            audience_id = data.get("audience_id")

            builder = AudinceBuilder(json=data, cache=False)
            valid, message = builder._validate_json_data()
            if not valid:
                return {'status': 'error', 'message': message}, 500

            final_result = builder.get_final_audience()
            popped_ids = {}

            # Iterate over the keys and values of the outer dictionary.
            if builder.audience_data:
                for key, value in builder.audience_data.items():
                    # Use .pop() to remove 'user_pseudo_ids' and store it in the new dictionary.
                    if "user_pseudo_ids" in value:
                        value.pop("user_pseudo_ids")
                        popped_ids[key] = value
                    
                timeNow = datetime.now(timezone).isoformat()
                data['result'] = popped_ids
                data['total_audience'] = len(final_result)
                data['lastupdate'] = timeNow
                
                fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/total_audience").set(len(final_result))
                fb.db.reference().child(f"account/{property_id}/audience/{audience_id}/lastupdate").set(timeNow)
                return {'status': 'ok', 'data': data}, 200
            else:
                return {'status': 'error', 'message': 'No audience data, please provide nodes and connections'}, 500
    
        return {'status': 'error', 'message': 'Method not allowed'}, 405
    except Exception as e:
        logging.error(e)
        return {'status': 'error', 'message': str(e)}, 500
    

@feature_audience_builder.route('/v2/list',  methods=['GET'])
@feature_audience_builder.route('/v2/list/',  methods=['GET'])
def feature_audience_builder_v2_list():
    try:
        if request.method == 'GET':
            data = request.args
            for req in ['property_id', 'type']:
                if req not in data:
                    return {"status":"error",'message': f"{req} is require"}, 400
            
            property_id = data.get('property_id')
            audience_type = data.get('type')
            if audience_type not in ['preset', 'builder', 'all']:
                return {'status': 'error', 'message': "type must be 'preset', 'builder', or 'all'"}
            context = fb.db.reference().child(f'account/{property_id}/audience').get()
            if context:
                returnAudience = []
                for a in context:
                    au = context[a]
                    if audience_type != 'all':
                        if au['type'] == audience_type:
                            returnContext = {
                                'active': au['active'],
                                'id': au['id'],
                                'name': au['name'],
                                'type': au['settings']['type'],
                                'createdate': au['createdate'],
                                'lastupdate': au['lastupdate'],
                                'total_audience': au['total_audience'],
                                'frequency': 'Fixed' if au['settings']['type'] == 'fixed' else f"{au['settings']['calculation']['type'].upper()} {au['settings']['calculation']['time']}"
                            }
                            returnAudience.append(returnContext)
                    else:
                        returnContext = {
                                'active': au['active'],
                                'id': au['id'],
                                'name': au['name'],
                                'type': au['settings']['type'],
                                'createdate': au['createdate'],
                                'lastupdate': au['lastupdate'],
                                'total_audience': au['total_audience'],
                                'frequency': 'Fixed' if au['settings']['type'] == 'fixed' else f"{au['settings']['calculation']['type'].upper()} {au['settings']['calculation']['time']}"
                            }
                        returnAudience.append(returnContext)
                #Add process get audience ad sync context
                final_pack = []
                for item in returnAudience:
                    au_id = item['id']
                    #Get ad context
                    ref = fb.db.reference(f"account/{property_id}/ad_audience_sync/{au_id}")
                    au_ad_context = ref.get()
                    item['audience_sync_data'] = au_ad_context
                    final_pack.append(item)
                return {'status': 'ok', 'data': final_pack}, 200
            else:
                return {'status': 'not fond', 'message': f'Property {property_id} has no audience'},404

        return {'status': 'error', 'message': 'Method not allowed'}, 405
    except Exception as e:
        logging.error(e)
        return {'status': 'error', 'message': str(e)}, 500
    
@feature_audience_builder.route('/v2/download',  methods=['GET'])
@feature_audience_builder.route('/v2/download/',  methods=['GET'])
def feature_audience_builder_v2_download():
    try:
        if request.method == 'GET':
            data = request.args
            for req in ['property_id', 'audience_id', 'limit']:
                if req not in data:
                    return {"status":"error",'message': f"{req} is require"}, 400
            
            property_id = data.get("property_id")
            audience_id = data.get("audience_id")
            limit = data.get("limit", 100)

            audience_context = fb.db.reference().child(f"account/{property_id}/audience/{audience_id}").get()
            
            if not audience_context:
                return {'status': 'error', 'message': f"Audience ID {audience_id} was not fond"}, 500
            
            builder = AudinceBuilder(json=audience_context, cache=False)
            valid, message = builder._validate_json_data()
            if not valid:
                return {'status': 'error', 'message': message}, 500

            final_result = builder.get_final_audience()

            if len(final_result) <= 0:
                return {'status': 'ok', 'data': []}, 500

            from utility.lookerSDK import LookerSDK
            import re
            looker = LookerSDK(property_id=property_id)

            audience_result = looker.download_audience_profile(final_result, limit)
            renamed = [
                {
                    'lastupdate_time': d["profile_explore.lastupdate_time"],
                    'user_pseudo_id': d["profile_explore.user_pseudo_id"],
                    'facebook_psid': d["profile_explore__user_property.facebook"],
                    'line_uid': d['profile_explore__user_property.line'],
                    'phonenumber': d['profile_explore__user_property.phonenumber'],
                    'email': d['profile_explore__user_property.email'],
                }
                for d in audience_result
            ]

            def clean_key(key: str) -> str:
                return re.split(r'[._]{2,}|[.]', key)[-1]

            def clean_value(val: str):
                try:
                    parsed = json.loads(val)
                    return parsed
                except (json.JSONDecodeError, TypeError):
                    return val

            renamed = [{clean_key(k): clean_value(v) for k, v in d.items()} for d in renamed]

            return {'status': 'ok', 'data': renamed}, 200
    
    except Exception as e:
        logging.error(e)
        return {'status': 'error', 'message': str(e)}, 500
    

@feature_audience_builder.route('/v2/table/list',  methods=['GET'])
@feature_audience_builder.route('/v2/table/list/',  methods=['GET'])
def feature_audience_builder_v2_offline_table_list():
    try:
        if request.method == 'GET':
            data = request.args
            for req in ['property_id', 'source']:
                if req not in data:
                    return {"status":"error",'message': f"{req} is require"}, 400
            
            property_id = data.get("property_id")
            source = data.get("source")
            if source not in ['event', 'user', 'offline', 'ga4']:
                return {'status': 'error', 'message': f"Source {source} was not supported"}, 400
            
            from utility.lookerSDK import LookerSDK
            looker = LookerSDK(property_id=property_id)
            
            #Looker schema for offline flow
            packs = []
            model = looker.sdk.lookml_model(f"c360_client_{looker.property_id}")
            explores = model.explores
            if source == 'offline':
                for ex in explores:
                    if ex.name.startswith("offline_"):
                        #Get explore
                        explore = looker.sdk.lookml_model_explore(f"c360_client_{looker.property_id}", ex.name)
                        pack = {
                            'name': explore.name,
                            'label': explore.label,
                            'description': explore.description
                        }
                        packs.append(pack)
                
                return {'status': 'ok', 'data': packs}, 200
            elif source == 'event':
                explore = looker.sdk.lookml_model_explore(f"c360_client_{looker.property_id}", "api_event")
                return {'status': 'ok', 'data': [
                    {
                        "name": explore.name,
                        "label": explore.label,
                        'description': explore.description
                    }
                ]}, 200
            elif source == 'user':
                explore = looker.sdk.lookml_model_explore(f"c360_client_{looker.property_id}", "profile_explore")
                return {'status': 'ok', 'data': [
                    {
                        "name": explore.name,
                        "label": explore.label,
                        'description': explore.description
                    }
                ]}, 200
            elif source == 'ga4':
                return {'status': 'ok', 'data': []}, 200
        
        return {'status': 'error', 'message': 'Method not allowed'}, 405
    except Exception as e:
        logging.error(e)
        return {'status': 'error', 'message': str(e)}, 500
    
@feature_audience_builder.route('/v2/schema/list',  methods=['GET'])
@feature_audience_builder.route('/v2/schema/list/',  methods=['GET'])
def feature_audience_builder_v2_schema_list():
    try:
        if request.method == 'GET':
            data = request.args
            for req in ['property_id', 'view']:
                if req not in data:
                    return {"status":"error",'message': f"{req} is require"}, 400
            
            property_id = data.get("property_id")
            view = data.get("view")

            from utility.lookerSDK import LookerSDK
            looker = LookerSDK(property_id=property_id)
            
            #Looker schema list
            packsDimension = []
            packsMeasure = []
            explore = looker.sdk.lookml_model_explore(f"c360_client_{property_id}", view)
            if not explore:
                return {'status': 'ok', 'message': f"View {view} was not found"}, 404
            
            dimensions = explore.fields.dimensions
            measures = explore.fields.measures
            #Dimensions
            for dim in dimensions:
                if not dim.hidden:
                    if dim.is_timeframe and dim.time_interval['name'] == 'second':
                        pack = {
                            "name": dim.name,
                            "label": dim.label_short,
                            "description": dim.description,
                            "category": dim.category.value,
                            "is_timeframe": dim.is_timeframe,
                            "time_interval": dim.time_interval['name'],
                        }
                        packsDimension.append(pack)
                    elif not dim.is_timeframe:
                        pack = {
                            "name": dim.name,
                            "label": dim.label_short,
                            "description": dim.description,
                            "category": dim.category.value,
                            "is_timeframe": dim.is_timeframe,
                            "time_interval": '-',
                        }
                        packsDimension.append(pack)
            #Measure
            for mea in measures:
                pack = {
                    "name": mea.name,
                    "label": mea.label_short,
                    "description": mea.description,
                    "category": mea.category.value,
                    "is_timeframe": mea.is_timeframe,
                    "time_interval": '-',
                }
                packsMeasure.append(pack)

            final_result = {
                "view": view,
                "dimension": packsDimension,
                "measure": packsMeasure
            }
            
            return {'status': 'ok', 'data': final_result}, 200
        
        return {'status': 'error', 'message': 'Method not allowed'}, 405
    except Exception as e:
        logging.error(e)
        return {'status': 'error', 'message': str(e)}, 500
    
@feature_audience_builder.route('/v2/value/list',  methods=['GET'])
@feature_audience_builder.route('/v2/value/list/',  methods=['GET'])
def feature_audience_builder_v2_value_list():
    try:
        if request.method == 'GET':
            data = request.args
            for req in ['property_id', 'view', 'dimension']:
                if req not in data:
                    return {"status":"error",'message': f"{req} is require"}, 400
            
            property_id = data.get("property_id")
            view = data.get("view")
            dimension = data.get("dimension")
            
            from utility.lookerSDK import LookerSDK
            looker = LookerSDK(property_id=property_id)

            query_obj = {
                "view": view,"fields": [dimension],
                "filters": {dimension: "-NULL"},
                "model": f"c360_client_{property_id}",
                "limit": "-1"
            }
            query = looker.sdk.create_query(query_obj)
            result = looker.sdk.run_query(query.id, result_format="json")
            result = json.loads(result)
            if result:
                return {'status': 'ok', 'data': result}, 200
            else:
                return {'status': 'ok', 'data': []}, 200

    except Exception as e:
        logging.error(e)
        return {'status': 'error', 'message': str(e)}, 500