from fastapi import Request, Query, Path, Depends, Header, APIRouter, HTTPException
from typing import List, Optional, Union, Literal, Dict, Any
from fastapi.responses import JSONResponse
from connectors.firebase.firebase import Firebase
from pydantic import ValidationError
import pytz
import os
import json
import uuid
from datetime import datetime, timedelta
from models.audience_builder import *
from utility.jsonschemaValidate import *
from utility.function import Function
# from feature.audience.queryBuilder import *
from api.feature.audience.node import *
from api.feature.audience.craft import BQCraft
from utility.dashboard.search import C360Search
from api.dashboard.profile import fucntion as profileFunction
from api.feature.audience.audience_builder import AudinceBuilder


import logging
logging.basicConfig(level=logging.INFO)
timezone_utc = pytz.utc

fb = Firebase(host=os.environ.get("FIREBASE_HOST"))

router = APIRouter()

LOGGING_PREFIX = "api_feature_audience"

@router.get("/v2/suggestion/dimension", response_model=DataResponse, description="Get suggestion dimension for audience builder")
async def feature_audience_builder_suggestion_dimension(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    source: Literal['event', 'ads', 'user', 'ga4', 'offline', 'message'] = Query(..., description="Data source type"),
):
    try:
        from api.feature.audience.craft import LookerDimension
        data = LookerDimension.getSuggestion(source)
        return JSONResponse(status_code=200, content={'status': 'ok', 'data': data, 'message': 'Success'})
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})

@router.get("/v2/suggestion/property", response_model=DataResponse, description="Get suggestion property for audience builder")
async def feature_audience_builder_suggestion_property(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    source: Literal['event', 'ads', 'user', 'ga4', 'offline', 'message'] = Query(..., description="Data source type"),
    dimension: str = Query(..., description="Dimension name"),
    date: Optional[str] = Query("7 days", description="Date filter in YYYY-MM-DD format")
):
    try:
        from connectors.looker.lookerSDK import LookerSDK
        looker = LookerSDK(property_id=property_id)
        data = looker.getDimensionUniqueValue(source, dimension, date)
        if data is None:
            data = []
        return JSONResponse(status_code=200, content={'status': 'ok', 'data': data, 'message': 'Success'})
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})
    
@router.get("/v2/suggestion/property/value", response_model=DataResponse, description="Get suggestion property for audience builder")
async def feature_audience_builder_suggestion_property_value(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    source: Literal['event', 'ads', 'user', 'ga4', 'offline', 'message'] = Query(..., description="Data source type"),
    dimension: str = Query(..., description="Dimension name"),
    date: Optional[str] = Query("7 days", description="Date filter in YYYY-MM-DD format"),
    parent_dimension: str = Query(None, description="Parent dimension name"),
    parent_value: str = Query(None, description="Parent dimension value")
):
    try:
        from connectors.looker.lookerSDK import LookerSDK
        looker = LookerSDK(property_id=property_id)
        data = looker.getDimensionUniqueValueProperty(source, dimension, parent_dimension, parent_value, date)
        if data is None:
            data = []
        return JSONResponse(status_code=200, content={'status': 'ok', 'data': data, 'message': 'Success'})
    except Exception as e:
            logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
            return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})

@router.post("/v2", description="Create audience using audience builder v2", response_model=DataResponse)
async def feature_audience_builder_create_v2(default_request: Request, request: AddAudience):
    try:
        # Generate audience ID if not provided
        request_data = request.model_dump()
        if not request_data.get('id'):
            request_data['id'] = str(uuid.uuid4())
        
        # Validate required fields before creating builder
        required_fields = ['property_id', 'id', 'name', 'nodes', 'connections', 'settings']
        missing_fields = [field for field in required_fields if field not in request_data]
        if missing_fields:
            error_msg = f"Missing required fields: {', '.join(missing_fields)}"
            logging.error(f"Error in {LOGGING_PREFIX}_create_v2: {error_msg}")
            return JSONResponse(status_code=400, content={'status': 'error', 'message': error_msg})
        
        builder = AudinceBuilder(json=request_data, cache=False)
        valid, message = builder._validate_json_data()
        if not valid:
            # Convert ValidationError to readable message
            if isinstance(message, ValidationError):
                error_details = []
                for error in message.errors():
                    field = '.'.join(str(loc) for loc in error.get('loc', []))
                    msg = error.get('msg', 'Validation error')
                    error_details.append(f"{field}: {msg}")
                error_msg = "Validation error: " + "; ".join(error_details)
            else:
                error_msg = str(message) if message else "Validation failed"
            logging.error(f"Error in {LOGGING_PREFIX}_create_v2: {error_msg}")
            return JSONResponse(status_code=400, content={'status': 'error', 'message': error_msg})
        now = datetime.now(timezone_utc)
        time = now.strftime('%Y-%m-%d %H:%M:%S')
        
        #Save to Friesbase
        fb.db.reference().child(f'account/{builder.property_id}/audience/{builder.audience_id}').set(request_data)
        fb.db.reference().child(f'account/{builder.property_id}/audience/{builder.audience_id}/active').set(False)
        fb.db.reference().child(f'account/{builder.property_id}/audience/{builder.audience_id}/createdate').set(time)
        fb.db.reference().child(f'account/{builder.property_id}/audience/{builder.audience_id}/lastupdate').set(time)
        fb.db.reference().child(f'account/{builder.property_id}/audience/{builder.audience_id}/total_audience').set(0)
        fb.db.reference().child(f'account/{builder.property_id}/audience/{builder.audience_id}/type').set("builder")

        data = request_data.copy()
        data['createdate'] = time
        data['lastupdate'] = time
        data['total_audience'] = 0
        data['active'] = False
        
        return {'status': 'ok', 'message': f'Audience ID {builder.audience_id} created succesfully', 'data': data},200
    except KeyError as e:
            error_msg = f"Missing required field in request data: {str(e)}"
            logging.error(f"Error in {LOGGING_PREFIX}_create_v2: {error_msg}", exc_info=True)
            return JSONResponse(status_code=400, content={'status': 'error', 'message': error_msg})
    except ValidationError as e:
            # Format ValidationError for better readability
            error_details = []
            if hasattr(e, 'errors'):
                for error in e.errors():
                    field = '.'.join(str(loc) for loc in error.get('loc', []))
                    msg = error.get('msg', 'Validation error')
                    error_details.append(f"{field}: {msg}")
            error_msg = "Validation error: " + ("; ".join(error_details) if error_details else str(e))
            logging.error(f"Error in {LOGGING_PREFIX}_create_v2: {error_msg}", exc_info=True)
            return JSONResponse(status_code=400, content={'status': 'error', 'message': error_msg})
    except Exception as e:
            error_msg = str(e) if str(e) else "Internal Server Error"
            logging.error(f"Error in {LOGGING_PREFIX}_create_v2: {error_msg}", exc_info=True)
            return JSONResponse(status_code=500, content={'status': 'error', 'message': error_msg})

@router.put("/v2", description="Update audience using audience builder v2")
async def feature_audience_builder_update_v2(default_request: Request, request: AudienceModel):
    try:
        # Check audience exist
        audience_exist = fb.db.reference().child(f"account/{request.property_id}/audience/{request.audience_id}").get(shallow=True)
        if not audience_exist:
            return JSONResponse(status_code=500, content={'status': 'error', 'message': f'No audience {request.audience_id} in this property'})

        # Convert AudienceModel to format expected by AudinceBuilder
        # AudienceModel uses 'audience_id' but AudinceBuilder expects 'id'
        request_data = request.model_dump()
        request_data['id'] = request.audience_id  # Map audience_id to id for AudinceBuilder
        # Keep audience_id in data for Firebase storage
        if 'audience_id' not in request_data:
            request_data['audience_id'] = request.audience_id

        builder = AudinceBuilder(json=request_data, cache=False)
        valid, message = builder._validate_json_data()
        if not valid:
            return JSONResponse(status_code=400, content={'status': 'error', 'message': message})
        
        if builder.connections != {}:
            final_result = builder.get_final_audience()
        else:
            final_result = []
        now = datetime.now(timezone_utc)
        time = now.strftime('%Y-%m-%d %H:%M:%S')
        
        #Save to Friesbase
        # Use request_data which has both 'id' and 'audience_id' for compatibility
        fb.db.reference().child(f'account/{builder.property_id}/audience/{builder.audience_id}').set(request_data)
        fb.db.reference().child(f'account/{builder.property_id}/audience/{builder.audience_id}/lastupdate').set(time)
        fb.db.reference().child(f'account/{builder.property_id}/audience/{builder.audience_id}/total_audience').set(len(final_result))

        return JSONResponse(status_code=200, content={'status': 'ok', 'message': f'Audience ID {builder.audience_id} updated succesfully'})
    except Exception as e:
            logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
            return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})
    
@router.get("/v2", description="Get audience using audience builder v2", response_model=DataResponse)
async def feature_audience_builder_get_v2(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    audience_id: str = Query(..., description="Audience ID"),
):
    try:
        audience_context = fb.db.reference().child(f'account/{property_id}/audience/{audience_id}').get()
        if not audience_context:
            return JSONResponse(status_code=404, content={'status': 'not found', 'message': 'Audience not found'})
        
        if 'nodes' not in audience_context:
            return JSONResponse(status_code=200, content = {'status': 'ok', 'data': audience_context, 'message': 'Success'})
        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 JSONResponse(status_code=200, content={'status': 'ok', 'data': audience_context, 'message': 'Success'})
        else:
            return JSONResponse(status_code=200, content={'status': 'ok', 'data': audience_context, 'message': 'Success'})
    except Exception as e:
            logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
            return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})

@router.post("/v2/status", description="Get audience build status using audience builder v2")
async def feature_audience_builder_status_v2(default_request: Request, request: UpdateAudienceStatus):
    try:
        now = datetime.now(timezone_utc)
        time = now.strftime('%Y-%m-%d %H:%M:%S')
        fb.db.reference().child(f'account/{request.property_id}/audience/{request.audience_id}/active').set(request.active)
        fb.db.reference().child(f'account/{request.property_id}/audience/{request.audience_id}/lastupdate').set(time)
        return JSONResponse(status_code=200, content={'status': 'ok', 'message': f"Update Audience ID {request.audience_id} to {'Active' if request.active else 'Inactive'} successfully"})
    except Exception as e:
            logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
            return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})

@router.post("/v2/execute", description="Execute audience build using audience builder v2")
async def feature_audience_builder_execute_v2(default_request: Request, request: AudienceModel):
    try:
        builder = AudinceBuilder(json=request.model_dump(), cache=False)
        valid, message = builder._validate_json_data()
        if not valid:
            return JSONResponse(status_code=400, content={'status': 'error', 'message': message})
        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
            
            data = request.model_dump()    
            timeNow = datetime.now().isoformat()
            data['result'] = popped_ids
            data['total_audience'] = len(final_result)
            # data['lastupdate'] = timeNow
            
            # fb.db.reference().child(f"account/{request.property_id}/audience/{request.audience_id}/lastupdate").set(timeNow)
            return JSONResponse(status_code=200, content={'status': 'ok', 'data': data, 'message': 'Success'})
        else:
            return JSONResponse(status_code=500, content={'status': 'error', 'message': 'No audience data, please provide nodes and connections'})
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})

# Pagination helper functions
def _apply_filters(items: List[dict], filters: List[str]) -> List[dict]:
    """Apply filters to items list"""
    if not filters or len(filters) == 0:
        return items
    
    search_filters = []
    for filter_str in filters:
        if ':' in filter_str:
            field, value = filter_str.split(':', 1)
            if field and value is not None:
                search_filters.append({"field": field, "value": value})
    
    if not search_filters:
        return items
    
    # Group filters by value (for OR search across different fields with same value)
    value_groups = {}
    for sf in search_filters:
        value = sf["value"]
        if value not in value_groups:
            value_groups[value] = []
        value_groups[value].append(sf["field"])
    
    # Apply filters
    filtered = []
    for item in items:
        matches_all_values = True
        for search_value, fields in value_groups.items():
            # Check if searchValue matches in ANY of the fields (OR across fields)
            value_matches = False
            for field in fields:
                field_value = item.get(field)
                if field_value is not None:
                    field_str = str(field_value).lower()
                    value_str = str(search_value).lower()
                    if value_str in field_str:  # Partial match (contains)
                        value_matches = True
                        break
            if not value_matches:
                matches_all_values = False
                break
        if matches_all_values:
            filtered.append(item)
    
    return filtered

@router.get('/v2/list', description="Get audience list using audience builder v2", response_model=DataResponse)
async def feature_audience_builder_list_v2(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    type: Optional[Literal['all','preset', 'builder']] = Query(None, description="Audience type filter"),
    page: Optional[int] = Query(1, description="Page number"),
    page_size: Optional[int] = Query(50, description="Page size"),
    status: Optional[Literal['all','active', 'inactive']] = Query('all', description="Audience status filter"),
    sort_by: Optional[Literal['lastupdate', 'createdate', 'name', 'total_audience']] = Query('lastupdate', description="Sort by field"),
    sort_order: Optional[Literal['asc', 'desc']] = Query('desc', description="Sort order"),
    filter: Optional[List[str]] = Query(None, description="Filter criteria in format field:value")
):
    try:
        context = fb.db.reference().child(f'account/{property_id}/audience').get()
        if not context:
            return JSONResponse(status_code=200, content={'status': 'ok', 'data': [], 'message': 'Success'})
        returnAudience = []
        for a in context:
            au = context[a]
            
            # Determine audience type: check 'type' field first, then check if it has 'nodes' (builder) or 'audience_syntax' (preset)
            audience_type = au.get('type')
            if not audience_type:
                # Fallback: determine type from structure
                if 'nodes' in au and 'connections' in au:
                    audience_type = 'builder'
                elif 'audience_syntax' in au or 'audience_name' in au:
                    audience_type = 'preset'
                else:
                    audience_type = 'builder'  # Default to builder if unclear
            
            # Filter by type if specified
            if type != 'all' and type is not None:
                if audience_type != type:
                    continue
            
            # Build return context - handle both preset and builder structures
            try:
                # Common fields
                returnContext = {
                    'active': au.get('active', au.get('status') == 'active'),
                    'id': au.get('id', a),  # Use key as id if id field missing
                    'name': au.get('name', au.get('audience_name', '')),
                    'createdate': au.get('createdate', ''),
                    'lastupdate': au.get('lastupdate', ''),
                    'total_audience': au.get('total_audience', au.get('audience_size', 0)),
                }
                
                # Type-specific fields
                if audience_type == 'builder' and 'settings' in au:
                    returnContext['type'] = au['settings'].get('type', 'dynamic')
                    if au['settings'].get('type') == 'fixed':
                        returnContext['frequency'] = 'Fixed'
                    else:
                        calc = au['settings'].get('calculation', {})
                        returnContext['frequency'] = f"{calc.get('type', 'daily').upper()} {calc.get('time', '10:00')}"
                else:
                    # Preset audience - no settings
                    returnContext['type'] = 'preset'
                    returnContext['frequency'] = 'Fixed'
                
                returnAudience.append(returnContext)
            except Exception as e:
                logging.error(f"Error processing audience {a}: {e}")
                continue
        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)
        #filter status
        if status != 'all':
            if status == 'active':
                final_pack = [fa for fa in final_pack if fa['active'] == True]
            elif status == 'inactive':
                final_pack = [fa for fa in final_pack if fa['active'] == False]
        
        # Apply filters (name, etc.)
        try:
            if filter:
                final_pack = _apply_filters(final_pack, filter)
        except Exception as filter_error:
            logging.error(f"Error applying filters: {filter_error}")
            # Continue without filtering if filter fails
        
        #Sort by lastupdate desc
        ordered_audience_desc = sorted(final_pack, key=lambda x: x[sort_by], reverse=(sort_order == 'desc'))
        #Pagination
        start_index = (page - 1) * page_size
        end_index = start_index + page_size
        paginated_audience = ordered_audience_desc[start_index:end_index]
        return JSONResponse(status_code=200, content={'status': 'ok', 'data': paginated_audience, 'message': 'Success'})
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})

@router.get("/v2/download", description="Download audience using audience builder v2", response_model=DataResponse)
async def feature_audience_builder_download_v2(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    audience_id: str = Query(..., description="Audience ID"),
    limit: Optional[int] = Query(100, description="Limit number of user_pseudo_id to download"),
    offset: Optional[int] = Query(0, description="Offset for pagination"),
):
    try:
        audience_context = fb.db.reference().child(f"account/{property_id}/audience/{audience_id}").get()
        if not audience_context:
            return JSONResponse(status_code=404, content={'status': 'not found', 'message': 'Audience not found'})
        
        # Determine audience type
        audience_type = audience_context.get('type')
        if not audience_type:
            # Fallback: determine type from structure
            if 'nodes' in audience_context and 'connections' in audience_context:
                audience_type = 'builder'
            elif 'audience_syntax' in audience_context or 'audience_name' in audience_context:
                audience_type = 'preset'
            else:
                audience_type = 'builder'  # Default to builder if unclear
        
        final_result = []
        
        # For Preset: Read from BigQuery audience_members table
        if audience_type == 'preset':
            from connectors.bigquery.bq import BigQuery
            bq = BigQuery()
            dataset_id = f"client_{property_id}"
            project_id = os.environ.get('GCP_PROJECT', 'customer-360-profile')
            table_ref = f"{project_id}.{dataset_id}.audience_members"
            
            # Query BigQuery for active members
            # Escape audience_id to prevent SQL injection
            safe_audience_id = audience_id.replace("'", "''")
            query = f"""
                SELECT DISTINCT user_pseudo_id
                FROM `{table_ref}`
                WHERE audience_id = '{safe_audience_id}'
                  AND is_active = TRUE
                ORDER BY user_pseudo_id
                LIMIT {limit}
                OFFSET {offset}
            """
            
            try:
                rows = bq.get_query(query)
                final_result = [row['user_pseudo_id'] for row in rows if 'user_pseudo_id' in row]
            except Exception as e:
                logging.error(f"Error querying BigQuery for Preset audience {audience_id}: {e}")
                # Fallback: try to read from Firebase if migration not done yet
                user_pseudo_ids = audience_context.get('user_pseudo_id') or audience_context.get('user_pseudo_ids')
                if user_pseudo_ids and isinstance(user_pseudo_ids, list):
                    final_result = user_pseudo_ids[offset:offset+limit] if offset else user_pseudo_ids[:limit]
                else:
                    final_result = []
        
        # For Builder: Use real-time calculation (existing logic)
        else:
            builder = AudinceBuilder(json=audience_context, cache=False)
            valid, message = builder._validate_json_data()
            if not valid:
                return JSONResponse(status_code=400, content={'status': 'error', 'message': message})
            
            final_result = builder.get_final_audience()
            # Apply offset and limit for Builder
            if offset:
                final_result = final_result[offset:]
            if limit:
                final_result = final_result[:limit]
        
        if len(final_result) <= 0:
            return JSONResponse(status_code=200, content={'status': 'ok', 'data': [], 'message': 'Success'})
        
        from connectors.looker.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 JSONResponse(status_code=200, content={'status': 'ok', 'data': renamed, 'message': 'Success'})
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})

@router.get("/v2/offline/table", response_model=DataResponse, description="Get offline table list for audience builder v2")
async def feature_audience_builder_offline_table_v2(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
):
    try:
        from connectors.looker.lookerSDK import LookerSDK
        looker = LookerSDK(property_id=property_id)
        model = looker.sdk.lookml_model(f"c360_client_{looker.property_id}")
        explores = model.explores
        packs = []
        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 JSONResponse(status_code=200, content={'status': 'ok', 'data': packs, 'message': 'Success'})
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})

@router.get("/v2/offline/{view}", response_model=DataResponse, description="Get offline table schema for audience builder v2")
async def feature_audience_builder_offline_schema_v2(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    view: str = Path(..., description="Offline table name"),
):
    try:
        from connectors.looker.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 JSONResponse(status_code=404, content={'status': 'ok', 'message': f"View {view} was not found"})
        
        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 JSONResponse(status_code=200, content={'status': 'ok', 'data': final_result, 'message': 'Success'})
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})
    
@router.get("/v2/offline/{view}/{dimension}/value", response_model=DataResponse, description="Get offline table schema for audience builder v2")
async def feature_audience_builder_offline_schema_v2(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    view: str = Path(..., description="Offline table name"),
    dimension: str = Path(..., description="Dimension name")
):
    try:
        from connectors.looker.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 JSONResponse(status_code=200, content={'status': 'ok', 'data': result, 'message': 'Success'})
        else:
            return JSONResponse(status_code=200, content={'status': 'ok', 'data': [], 'message': 'Success'})
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})