from fastapi import Request, Query, Depends, Header, APIRouter, HTTPException, UploadFile, File, Form, Body
from fastapi.responses import JSONResponse
from utility.function import Function
from connectors.firebase.firebase import Firebase
from connectors.cloudStorage.bucketstorage import Storage
from google.cloud import storage as gcs_storage
import pytz
import os
import uuid
import base64
import re
from datetime import datetime
from werkzeug.utils import secure_filename
from models.content import *
from typing import Optional, List, Literal, Tuple

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_content"

# 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

def _apply_sort(items: List[dict], sort_by: Optional[str], order: Optional[str]) -> List[dict]:
    """Apply sorting to items list"""
    if not sort_by:
        return items
    
    order_desc = order == "desc"
    # Use sorted() to avoid modifying original list
    return sorted(items, key=lambda x: (x.get(sort_by) is None, x.get(sort_by)), reverse=order_desc)

def _apply_pagination(items: List[dict], offset: int, limit: int) -> Tuple[List[dict], dict]:
    """Apply pagination to items list"""
    total = len(items)
    paginated_items = items[offset:offset + limit] if limit > 0 else items[offset:]
    
    pagination = {
        "offset": offset,
        "limit": limit if limit > 0 else total,
        "total": total,
        "hasMore": offset + limit < total if limit > 0 else False
    }
    
    return paginated_items, pagination

# Validation helper functions
def _validate_sms_message(value: str, is_unicode: bool = False) -> None:
    """Validate SMS message text"""
    if not value or not isinstance(value, str) or not value.strip():
        raise HTTPException(400, detail="message must be a non-empty string")
    
    max_length_unicode = 70
    max_length_standard = 160
    max_length_total = 1000
    
    message_length = len(value)
    
    if message_length > max_length_total:
        raise HTTPException(400, detail=f"message exceeds maximum length of {max_length_total} characters")
    
    if is_unicode and message_length > max_length_unicode:
        raise HTTPException(400, detail=f"message exceeds maximum length of {max_length_unicode} characters for unicode SMS")
    elif not is_unicode and message_length > max_length_standard:
        raise HTTPException(400, detail=f"message exceeds maximum length of {max_length_standard} characters for standard SMS")

def _validate_email_subject(value: str) -> None:
    """Validate email subject line"""
    if not value or not isinstance(value, str) or not value.strip():
        raise HTTPException(400, detail="subject must be a non-empty string")
    
    max_length = 200
    if len(value) > max_length:
        raise HTTPException(400, detail=f"subject exceeds maximum length of {max_length} characters")

def _validate_email_body(value: str) -> None:
    """Validate email body content"""
    if not value or not isinstance(value, str) or not value.strip():
        raise HTTPException(400, detail="body must be a non-empty string")
    
    max_length = 100 * 1024  # 100KB
    if len(value) > max_length:
        raise HTTPException(400, detail=f"body exceeds maximum length of {max_length / 1024}KB")

def _validate_email_address(value: str) -> None:
    """Validate email address format"""
    if value is None or value == '':
        return  # Optional field
    
    if not isinstance(value, str):
        raise HTTPException(400, detail="email must be a string")
    
    email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    if not re.match(email_pattern, value.strip()):
        raise HTTPException(400, detail="email must be a valid email address")

@router.post("/image/upload", description="Upload an image for content")
async def feature_content_image_upload(default_request: Request, file: UploadFile = File(...)):
    try:
        if file.content_type != "image/jpeg":
            raise HTTPException(400, detail="Content-Type must be image/jpeg")

        image_data = await file.read()
        if not image_data:
            raise HTTPException(400, detail="No selected image")
                
        now = datetime.now(timezone_utc)
        time_now = int(now.timestamp())
        generate_image_file_name = f"""{uuid.uuid4()}_{time_now}.png"""
        filename = secure_filename(generate_image_file_name)
        gcs_blob_name = f"content/{filename}"
        
        try:
            storage = Storage(project_id=os.environ.get("GCP_PROJECT"),bucket_name=os.environ.get("GC_BUCKET_NAME"))

            link = storage.upload_from_byte(file_path=gcs_blob_name, image_bytes=image_data)

            if not link:
                raise HTTPException(500, detail="Failed to upload image to GCS")

            return JSONResponse(status_code=201, content={"status": "ok", "message": "Image uploaded successfully", "image_address": link})

        except Exception as e:
            logging.exception("Error processing upload")
            raise HTTPException(500, detail=str(e))
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        raise HTTPException(500, detail=str(e))

@router.post("/line", description="Create a new line content")
async def feature_content_line_crate(default_request: Request, request: CreateContent):
    try:
        now = datetime.now(timezone_utc)
        time = now.strftime('%Y-%m-%d %H:%M:%S')
        user_id = Function.getUserIDFromHeader(default_request.headers)
        contentId = Function.generate_uuid_from_text(f"{now}_{request.name}")
        
        #Save content to FB
        fb.db.reference().child(f"account/{request.property_id}/content/line/{contentId}/name").set(request.name)
        fb.db.reference().child(f"account/{request.property_id}/content/line/{contentId}/json").set(request.body)
        fb.db.reference().child(f"account/{request.property_id}/content/line/{contentId}/createdate").set(time)
        fb.db.reference().child(f"account/{request.property_id}/content/line/{contentId}/lastupdate").set(time)
        fb.db.reference().child(f"account/{request.property_id}/content/line/{contentId}/lastupdate_by").set(user_id)
        
        if request.json_preivew:
            fb.db.reference().child(f"account/{request.property_id}/content/line/{contentId}/json_preivew").set(request.json_preivew)
        
        return JSONResponse(status_code=201, content={'status': 'ok', 'message': f'Content {request.name} was created successfully', "content_id": contentId})

    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("/line", response_model=DataResponse, description="Get line content details")
async def feature_content_line_list(
    default_request: Request,
    params: GetContent = Depends(),
    offset: Optional[int] = Query(0, ge=0, description="Number of records to skip"),
    limit: Optional[int] = Query(20, ge=1, le=100, description="Number of records to return"),
    filter: Optional[List[str]] = Query(None, description="Filter criteria in format field:value"),
    sort_by: Optional[str] = Query(None, description="Field to sort by"),
    order: Optional[Literal["asc", "desc"]] = Query("asc", description="Sort order")
):
    try:
        if params.content_id != 'all':
            # Single content item - return without pagination
            newListContent = fb.db.reference().child(f"account/{params.property_id}/content/line/{params.content_id}").get()
            if not newListContent:
                return JSONResponse(status_code=404, content={'status': 'not_found', 'message': 'No content found', 'data': []})
            return JSONResponse(status_code=200, content={'status': 'ok', 'message': 'Content retrieved successfully', 'data': [newListContent]})
        else:
            contentData = fb.db.reference().child(f"account/{params.property_id}/content/line").get()
            if not contentData:
                return JSONResponse(status_code=404, content={'status': 'not_found', 'message': 'No content created', 'data': []})
            newListContent = []
            for con in contentData:
                context = contentData[con]
                context['content_id'] = con
                newListContent.append(context)
        
        if newListContent:
            # Apply filters
            if filter:
                newListContent = _apply_filters(newListContent, filter)
            
            # Apply sorting (default to createdate desc if no sort_by specified)
            if sort_by:
                newListContent = _apply_sort(newListContent, sort_by, order)
            else:
                # Default sort by createdate desc
                newListContent = sorted(newListContent, key=lambda x: x.get('createdate', ''), reverse=True)
            
            # Apply pagination
            items, pagination = _apply_pagination(newListContent, offset, limit)
            
            # Return pagination format
            return JSONResponse(status_code=200, content={
                'status': 'ok',
                'message': 'Content retrieved successfully',
                'data': {
                    'items': items,
                    'pagination': pagination
                }
            })
        else:
            return JSONResponse(status_code=404, content={'status': 'not_found', 'message': 'No content found', 'data': {'items': [], 'pagination': {'offset': offset, 'limit': limit, 'total': 0, 'hasMore': False}}})
    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.put("/line", description="Update an existing line content")
async def feature_content_line_update(default_request: Request, request: CreateContent):
    try:
        now = datetime.now(timezone_utc)
        time = now.strftime('%Y-%m-%d %H:%M:%S')
        user_id = Function.getUserIDFromHeader(default_request.headers)

        name = request.name if 'name' in request else fb.db.reference().child(f"account/{request.property_id}/content/line/{request.content_id}/name").get()
        body = request.body if 'body' in request else fb.db.reference().child(f"account/{request.property_id}/content/line/{request.content_id}/json").get()
        json_preview = request.json_preview if 'json_preview' in request else fb.db.reference().child(f"account/{request.property_id}/content/line/{request.content_id}/json_preview").get()

        #Update
        fb.db.reference().child(f"account/{request.property_id}/content/line/{request.content_id}/lastupdate").set(time)
        fb.db.reference().child(f"account/{request.property_id}/content/line/{request.content_id}/name").set(name)
        fb.db.reference().child(f"account/{request.property_id}/content/line/{request.content_id}/json").set(body)
        fb.db.reference().child(f"account/{request.property_id}/content/line/{request.content_id}/json_preview").set(json_preview)
        fb.db.reference().child(f"account/{request.property_id}/content/line/{request.content_id}/lastupdate_by").set(user_id)
        
        return JSONResponse(status_code=200, content={'status': 'ok', 'message': f'Content {name} was updated 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.delete("/line", description="Delete a line content")
async def feature_content_line_delete(default_request: Request, request: GetContent):
    try:
        #Delete process
        fb.db.reference().child(f"account/{request.property_id}/content/line/{request.content_id}").delete()
        return JSONResponse(status_code=200, content={'status': 'ok', 'message': f'Content {request.content_id} was deleted 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.get("/line/automation", response_model=DataResponse, description="Get list of automations using the line content")
async def feature_content_line_automation_list(default_request: Request, params: GetContent = Depends()):
    try:
        now = datetime.now(timezone_utc).strftime("%Y-%m-%d %H:%M")
        contentAutomations = fb.db.reference().child(f"account/{params.property_id}/content/line/{params.content_id}/automations").get()
        if contentAutomations:
            
            # Loop get name
            from utility.dashboard.genQuery import GenerateQuery
            from connectors.cloudSQL.cloudsql import CloudSQL
            csql = CloudSQL("asia-southeast1", os.environ.get("INSTANCE_NAME"))
            csql.create_engine(os.environ.get("POSTGRES_USER"), os.environ.get("POSTGRES_PASSWORD"), os.environ.get("POSTGRES_DB"))
            
            listAutomation = []
            for auto in contentAutomations:
                autoName = fb.db.reference().child(f"account/{params.property_id}/automation/{auto}/name").get()

                genq = GenerateQuery(property_id=params.property_id)
                query = genq.getNextSchedual(automation_id=auto, now=now)
                result = csql.query(query)
                nextSchedual = result[0][0].strftime("%Y-%m-%d %H:%M") if result[0][0] else 'Automation not active'

                #Get next push
                packAuto = {"automation_id": auto,"automation_name": autoName,"next_schedual": nextSchedual}
                listAutomation.append(packAuto)
            return JSONResponse(status_code=200, content={'status': 'ok', 'message': 'Automation retrieved successfully', 'data': listAutomation})
        return JSONResponse(status_code=404, content={'status': 'not_found', 'message': 'No automation found', 'data': []})
    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("/facebook", description="Create a new facebook content")
async def feature_content_facebook_crate(default_request: Request, request: CreateContent):
    try:
        now = datetime.now(timezone_utc).strftime("%Y-%m-%d %H:%M")
        user_id = Function.getUserIDFromHeader(default_request.headers)
        contentId = Function.generate_uuid_from_text(f"{now}_{request.name}")
        
        #Save content to FB
        fb.db.reference().child(f"account/{request.property_id}/content/facebook/{contentId}/name").set(request.name)
        fb.db.reference().child(f"account/{request.property_id}/content/facebook/{contentId}/json").set(request.body)
        fb.db.reference().child(f"account/{request.property_id}/content/facebook/{contentId}/createdate").set(now)
        fb.db.reference().child(f"account/{request.property_id}/content/facebook/{contentId}/lastupdate").set(now)
        fb.db.reference().child(f"account/{request.property_id}/content/facebook/{contentId}/lastupdate_by").set(user_id)

        return JSONResponse(status_code=200, content={'status': 'ok', 'message': f'Content {request.name} was created successfully', "content_id": contentId})
    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("/facebook", response_model=DataResponse, description="Get facebook content details")
async def feature_content_facebook_list(
    default_request: Request,
    params: GetContent = Depends(),
    offset: Optional[int] = Query(0, ge=0, description="Number of records to skip"),
    limit: Optional[int] = Query(20, ge=1, le=100, description="Number of records to return"),
    filter: Optional[List[str]] = Query(None, description="Filter criteria in format field:value"),
    sort_by: Optional[str] = Query(None, description="Field to sort by"),
    order: Optional[Literal["asc", "desc"]] = Query("asc", description="Sort order")
):
    try:
        content_id = params.content_id
        property_id = params.property_id
        if content_id != 'all':
            # Single content item - return without pagination
            newListContent = fb.db.reference().child(f"account/{property_id}/content/facebook/{content_id}").get()
            if not newListContent:
                return JSONResponse(status_code=404, content={'status': 'not_found', 'message': 'No content found', 'data': []})
            return JSONResponse(status_code=200, content={'status': 'ok', 'message': 'Content retrieved successfully', 'data': [newListContent]})
        else:
            contentData = fb.db.reference().child(f"account/{property_id}/content/facebook").get()
            if not contentData:
                return JSONResponse(status_code=404, content={'status': 'not_found', 'message': 'No content created', 'data': []})
            newListContent = []
            for con in contentData:
                context = contentData[con]
                context['content_id'] = con
                newListContent.append(context)
        
        if newListContent:
            # Apply filters
            if filter:
                newListContent = _apply_filters(newListContent, filter)
            
            # Apply sorting (default to createdate desc if no sort_by specified)
            if sort_by:
                newListContent = _apply_sort(newListContent, sort_by, order)
            else:
                # Default sort by createdate desc
                newListContent = sorted(newListContent, key=lambda x: x.get('createdate', ''), reverse=True)
            
            # Apply pagination
            items, pagination = _apply_pagination(newListContent, offset, limit)
            
            # Return pagination format
            return JSONResponse(status_code=200, content={
                'status': 'ok',
                'message': 'Content retrieved successfully',
                'data': {
                    'items': items,
                    'pagination': pagination
                }
            })
        else:
            return JSONResponse(status_code=404, content={'status': 'not_found', 'message': 'No content found', 'data': {'items': [], 'pagination': {'offset': offset, 'limit': limit, 'total': 0, 'hasMore': False}}})
    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.put("/facebook", description="Update an existing facebook content")
async def feature_content_facebook_update(default_request: Request, request: CreateContent):
    try:
        now = datetime.now(timezone_utc).strftime("%Y-%m-%d %H:%M")
        user_id = Function.getUserIDFromHeader(default_request.headers)

        name = request.name if 'name' in request else fb.db.reference().child(f"account/{request.property_id}/content/facebook/{request.content_id}/name").get()
        body = request.body if 'body' in request else fb.db.reference().child(f"account/{request.property_id}/content/facebook/{request.content_id}/json").get()

        #Update
        fb.db.reference().child(f"account/{request.property_id}/content/facebook/{request.content_id}/lastupdate").set(now)
        fb.db.reference().child(f"account/{request.property_id}/content/facebook/{request.content_id}/name").set(name)
        fb.db.reference().child(f"account/{request.property_id}/content/facebook/{request.content_id}/json").set(body)
        fb.db.reference().child(f"account/{request.property_id}/content/facebook/{request.content_id}/lastupdate_by").set(user_id)
        
        return JSONResponse(status_code=200, content={'status': 'ok', 'message': f'Content {name} was updated 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.delete("/facebook", description="Delete a facebook content")
async def feature_content_facebook_delete(default_request: Request, request: GetContent):
    try:
        #Delete process
        fb.db.reference().child(f"account/{request.property_id}/content/facebook/{request.content_id}").delete()
        return JSONResponse(status_code=200, content={'status': 'ok', 'message': f'Content {request.content_id} was deleted 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)})

# SMS Content Endpoints
@router.post("/sms", description="Create a new SMS content")
async def feature_content_sms_create(default_request: Request, request: CreateSMSContent):
    try:
        now = datetime.now(timezone_utc)
        time = now.strftime('%Y-%m-%d %H:%M:%S')
        user_id = Function.getUserIDFromHeader(default_request.headers)
        
        # Validate SMS message
        _validate_sms_message(request.message, request.unicode)
        
        contentId = Function.generate_uuid_from_text(f"{now}_{request.name}")
        
        # Save content to FB
        fb.db.reference().child(f"account/{request.property_id}/content/sms/{contentId}/name").set(request.name)
        fb.db.reference().child(f"account/{request.property_id}/content/sms/{contentId}/message").set(request.message)
        fb.db.reference().child(f"account/{request.property_id}/content/sms/{contentId}/createdate").set(time)
        fb.db.reference().child(f"account/{request.property_id}/content/sms/{contentId}/lastupdate").set(time)
        fb.db.reference().child(f"account/{request.property_id}/content/sms/{contentId}/lastupdate_by").set(user_id)
        
        if request.sender_id:
            fb.db.reference().child(f"account/{request.property_id}/content/sms/{contentId}/sender_id").set(request.sender_id)
        
        if request.unicode is not None:
            fb.db.reference().child(f"account/{request.property_id}/content/sms/{contentId}/unicode").set(request.unicode)
        
        return JSONResponse(status_code=201, content={'status': 'ok', 'message': f'Content {request.name} was created successfully', "content_id": contentId})
    except HTTPException:
        raise
    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("/sms", response_model=DataResponse, description="Get SMS content details")
async def feature_content_sms_list(
    default_request: Request,
    params: GetContent = Depends(),
    offset: Optional[int] = Query(0, ge=0, description="Number of records to skip"),
    limit: Optional[int] = Query(20, ge=1, le=100, description="Number of records to return"),
    filter: Optional[List[str]] = Query(None, description="Filter criteria in format field:value"),
    sort_by: Optional[str] = Query(None, description="Field to sort by"),
    order: Optional[Literal["asc", "desc"]] = Query("asc", description="Sort order")
):
    try:
        content_id = params.content_id
        property_id = params.property_id
        if content_id != 'all':
            # Single content item - return without pagination
            newListContent = fb.db.reference().child(f"account/{property_id}/content/sms/{content_id}").get()
            if not newListContent:
                return JSONResponse(status_code=404, content={'status': 'not_found', 'message': 'No content found', 'data': []})
            return JSONResponse(status_code=200, content={'status': 'ok', 'message': 'Content retrieved successfully', 'data': [newListContent]})
        else:
            contentData = fb.db.reference().child(f"account/{property_id}/content/sms").get()
            if not contentData:
                return JSONResponse(status_code=404, content={'status': 'not_found', 'message': 'No content created', 'data': []})
            newListContent = []
            for con in contentData:
                context = contentData[con]
                context['content_id'] = con
                newListContent.append(context)
        
        if newListContent:
            # Apply filters
            if filter:
                newListContent = _apply_filters(newListContent, filter)
            
            # Apply sorting (default to createdate desc if no sort_by specified)
            if sort_by:
                newListContent = _apply_sort(newListContent, sort_by, order)
            else:
                # Default sort by createdate desc
                newListContent = sorted(newListContent, key=lambda x: x.get('createdate', ''), reverse=True)
            
            # Apply pagination
            items, pagination = _apply_pagination(newListContent, offset, limit)
            
            # Return pagination format
            return JSONResponse(status_code=200, content={
                'status': 'ok',
                'message': 'Content retrieved successfully',
                'data': {
                    'items': items,
                    'pagination': pagination
                }
            })
        else:
            return JSONResponse(status_code=404, content={'status': 'not_found', 'message': 'No content found', 'data': {'items': [], 'pagination': {'offset': offset, 'limit': limit, 'total': 0, 'hasMore': False}}})
    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.put("/sms", description="Update an existing SMS content")
async def feature_content_sms_update(default_request: Request, request: CreateSMSContent):
    try:
        if not request.content_id:
            raise HTTPException(400, detail="content_id is required for update")
        
        now = datetime.now(timezone_utc)
        time = now.strftime('%Y-%m-%d %H:%M:%S')
        user_id = Function.getUserIDFromHeader(default_request.headers)
        
        # Get fields that were actually set in the request
        request_dict = request.model_dump(exclude_unset=True)
        
        # Get existing values if not provided
        name = request.name if 'name' in request_dict else fb.db.reference().child(f"account/{request.property_id}/content/sms/{request.content_id}/name").get()
        message = request.message if 'message' in request_dict else fb.db.reference().child(f"account/{request.property_id}/content/sms/{request.content_id}/message").get()
        
        # Validate SMS message if provided
        if 'message' in request_dict:
            unicode_val = request.unicode if request.unicode is not None else fb.db.reference().child(f"account/{request.property_id}/content/sms/{request.content_id}/unicode").get() or False
            _validate_sms_message(request.message, unicode_val)
        
        # Update
        fb.db.reference().child(f"account/{request.property_id}/content/sms/{request.content_id}/lastupdate").set(time)
        fb.db.reference().child(f"account/{request.property_id}/content/sms/{request.content_id}/name").set(name)
        if 'message' in request_dict:
            fb.db.reference().child(f"account/{request.property_id}/content/sms/{request.content_id}/message").set(request.message)
        fb.db.reference().child(f"account/{request.property_id}/content/sms/{request.content_id}/lastupdate_by").set(user_id)
        
        if request.sender_id is not None:
            fb.db.reference().child(f"account/{request.property_id}/content/sms/{request.content_id}/sender_id").set(request.sender_id)
        
        if request.unicode is not None:
            fb.db.reference().child(f"account/{request.property_id}/content/sms/{request.content_id}/unicode").set(request.unicode)
        
        return JSONResponse(status_code=200, content={'status': 'ok', 'message': f'Content {name} was updated successfully'})
    except HTTPException:
        raise
    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.delete("/sms", description="Delete a SMS content")
async def feature_content_sms_delete(default_request: Request, request: GetContent):
    try:
        # Delete process
        fb.db.reference().child(f"account/{request.property_id}/content/sms/{request.content_id}").delete()
        return JSONResponse(status_code=200, content={'status': 'ok', 'message': f'Content {request.content_id} was deleted 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)})

# Email Content Endpoints
@router.post("/email", description="Create a new email content")
async def feature_content_email_create(default_request: Request, request: CreateEmailContent):
    try:
        now = datetime.now(timezone_utc)
        time = now.strftime('%Y-%m-%d %H:%M:%S')
        user_id = Function.getUserIDFromHeader(default_request.headers)
        
        # Validate email fields
        _validate_email_subject(request.subject)
        _validate_email_body(request.body)
        if request.from_email:
            _validate_email_address(request.from_email)
        
        contentId = Function.generate_uuid_from_text(f"{now}_{request.name}")
        
        # Save content to FB
        fb.db.reference().child(f"account/{request.property_id}/content/email/{contentId}/name").set(request.name)
        fb.db.reference().child(f"account/{request.property_id}/content/email/{contentId}/subject").set(request.subject)
        fb.db.reference().child(f"account/{request.property_id}/content/email/{contentId}/body").set(request.body)
        fb.db.reference().child(f"account/{request.property_id}/content/email/{contentId}/createdate").set(time)
        fb.db.reference().child(f"account/{request.property_id}/content/email/{contentId}/lastupdate").set(time)
        fb.db.reference().child(f"account/{request.property_id}/content/email/{contentId}/lastupdate_by").set(user_id)
        
        if request.from_email:
            fb.db.reference().child(f"account/{request.property_id}/content/email/{contentId}/from_email").set(request.from_email)
        
        if request.from_name:
            fb.db.reference().child(f"account/{request.property_id}/content/email/{contentId}/from_name").set(request.from_name)
        
        if request.is_html is not None:
            fb.db.reference().child(f"account/{request.property_id}/content/email/{contentId}/is_html").set(request.is_html)
        
        return JSONResponse(status_code=201, content={'status': 'ok', 'message': f'Content {request.name} was created successfully', "content_id": contentId})
    except HTTPException:
        raise
    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("/email", response_model=DataResponse, description="Get email content details")
async def feature_content_email_list(
    default_request: Request,
    params: GetContent = Depends(),
    offset: Optional[int] = Query(0, ge=0, description="Number of records to skip"),
    limit: Optional[int] = Query(20, ge=1, le=100, description="Number of records to return"),
    filter: Optional[List[str]] = Query(None, description="Filter criteria in format field:value"),
    sort_by: Optional[str] = Query(None, description="Field to sort by"),
    order: Optional[Literal["asc", "desc"]] = Query("asc", description="Sort order")
):
    try:
        content_id = params.content_id
        property_id = params.property_id
        if content_id != 'all':
            # Single content item - return without pagination
            newListContent = fb.db.reference().child(f"account/{property_id}/content/email/{content_id}").get()
            if not newListContent:
                return JSONResponse(status_code=404, content={'status': 'not_found', 'message': 'No content found', 'data': []})
            return JSONResponse(status_code=200, content={'status': 'ok', 'message': 'Content retrieved successfully', 'data': [newListContent]})
        else:
            contentData = fb.db.reference().child(f"account/{property_id}/content/email").get()
            if not contentData:
                return JSONResponse(status_code=404, content={'status': 'not_found', 'message': 'No content created', 'data': []})
            newListContent = []
            for con in contentData:
                context = contentData[con]
                context['content_id'] = con
                newListContent.append(context)
        
        if newListContent:
            # Apply filters
            if filter:
                newListContent = _apply_filters(newListContent, filter)
            
            # Apply sorting (default to createdate desc if no sort_by specified)
            if sort_by:
                newListContent = _apply_sort(newListContent, sort_by, order)
            else:
                # Default sort by createdate desc
                newListContent = sorted(newListContent, key=lambda x: x.get('createdate', ''), reverse=True)
            
            # Apply pagination
            items, pagination = _apply_pagination(newListContent, offset, limit)
            
            # Return pagination format
            return JSONResponse(status_code=200, content={
                'status': 'ok',
                'message': 'Content retrieved successfully',
                'data': {
                    'items': items,
                    'pagination': pagination
                }
            })
        else:
            return JSONResponse(status_code=404, content={'status': 'not_found', 'message': 'No content found', 'data': {'items': [], 'pagination': {'offset': offset, 'limit': limit, 'total': 0, 'hasMore': False}}})
    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.put("/email", description="Update an existing email content")
async def feature_content_email_update(default_request: Request, request: CreateEmailContent):
    try:
        if not request.content_id:
            raise HTTPException(400, detail="content_id is required for update")
        
        now = datetime.now(timezone_utc)
        time = now.strftime('%Y-%m-%d %H:%M:%S')
        user_id = Function.getUserIDFromHeader(default_request.headers)
        
        # Get fields that were actually set in the request
        request_dict = request.model_dump(exclude_unset=True)
        
        # Get existing values if not provided
        name = request.name if 'name' in request_dict else fb.db.reference().child(f"account/{request.property_id}/content/email/{request.content_id}/name").get()
        subject = request.subject if 'subject' in request_dict else fb.db.reference().child(f"account/{request.property_id}/content/email/{request.content_id}/subject").get()
        body = request.body if 'body' in request_dict else fb.db.reference().child(f"account/{request.property_id}/content/email/{request.content_id}/body").get()
        
        # Validate email fields if provided
        if 'subject' in request_dict:
            _validate_email_subject(request.subject)
        if 'body' in request_dict:
            _validate_email_body(request.body)
        if request.from_email:
            _validate_email_address(request.from_email)
        
        # Update
        fb.db.reference().child(f"account/{request.property_id}/content/email/{request.content_id}/lastupdate").set(time)
        fb.db.reference().child(f"account/{request.property_id}/content/email/{request.content_id}/name").set(name)
        if 'subject' in request_dict:
            fb.db.reference().child(f"account/{request.property_id}/content/email/{request.content_id}/subject").set(request.subject)
        if 'body' in request_dict:
            fb.db.reference().child(f"account/{request.property_id}/content/email/{request.content_id}/body").set(request.body)
        fb.db.reference().child(f"account/{request.property_id}/content/email/{request.content_id}/lastupdate_by").set(user_id)
        
        if request.from_email is not None:
            fb.db.reference().child(f"account/{request.property_id}/content/email/{request.content_id}/from_email").set(request.from_email)
        
        if request.from_name is not None:
            fb.db.reference().child(f"account/{request.property_id}/content/email/{request.content_id}/from_name").set(request.from_name)
        
        if request.is_html is not None:
            fb.db.reference().child(f"account/{request.property_id}/content/email/{request.content_id}/is_html").set(request.is_html)
        
        return JSONResponse(status_code=200, content={'status': 'ok', 'message': f'Content {name} was updated successfully'})
    except HTTPException:
        raise
    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.delete("/email", description="Delete an email content")
async def feature_content_email_delete(default_request: Request, request: GetContent):
    try:
        # Delete process
        fb.db.reference().child(f"account/{request.property_id}/content/email/{request.content_id}").delete()
        return JSONResponse(status_code=200, content={'status': 'ok', 'message': f'Content {request.content_id} was deleted 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)})

# Email File Upload Endpoints
@router.post("/email/upload", description="Upload email files")
async def feature_content_email_upload(default_request: Request, request: EmailUploadRequest = Body(...)):
    try:
        property_id = request.property_id
        file_name = request.file_name
        file_data = request.file_data
        folder = request.folder or "email"
        
        # Validate file_data (base64 string)
        if not isinstance(file_data, str):
            raise HTTPException(400, detail="file_data must be a base64 encoded string")
        
        # Decode base64 to bytes
        try:
            # Handle data URL format (data:image/png;base64,...) if present
            if ',' in file_data:
                file_data = file_data.split(',')[1]
            
            file_bytes = base64.b64decode(file_data)
            if not file_bytes:
                raise HTTPException(400, detail="Invalid base64 encoded data")
        except Exception as e:
            logging.error(f"Error decoding base64: {e}")
            raise HTTPException(400, detail=f"Failed to decode base64 data: {str(e)}")
        
        # Validate file size (max 10MB)
        max_size = 10 * 1024 * 1024  # 10MB
        if len(file_bytes) > max_size:
            raise HTTPException(400, detail=f"File size exceeds maximum allowed size of {max_size / (1024*1024)}MB")
        
        # Get file extension from file_name
        file_extension = os.path.splitext(file_name)[1].lower()
        if not file_extension:
            file_extension = '.jpg'  # default extension
        
        # Generate unique filename with timestamp
        now = datetime.now(timezone_utc)
        time_now = int(now.timestamp())
        base_name = os.path.splitext(secure_filename(file_name))[0]
        unique_filename = f"{base_name}_{uuid.uuid4().hex[:8]}_{time_now}{file_extension}"
        
        # Determine content type based on extension
        content_type_map = {
            '.jpg': 'image/jpeg',
            '.jpeg': 'image/jpeg',
            '.png': 'image/png',
            '.gif': 'image/gif',
            '.pdf': 'application/pdf',
            '.doc': 'application/msword',
            '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            '.xls': 'application/vnd.ms-excel',
            '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        }
        content_type = content_type_map.get(file_extension, 'application/octet-stream')
        
        # Construct GCS path: {property_id}/email/{filename}
        gcs_blob_name = f"{property_id}/{folder}/{unique_filename}"
        
        try:
            # Upload to GCS - use c360-public-resource bucket
            # Use Google Cloud Storage client directly to set proper content_type
            client = gcs_storage.Client(project=os.environ.get("GCP_PROJECT"))
            bucket = client.bucket("c360-public-resource")
            blob = bucket.blob(gcs_blob_name)
            
            blob.upload_from_string(file_bytes, content_type=content_type)
            # Bucket uses uniform bucket-level access: avoid per-object ACL
            public_url = f"https://storage.googleapis.com/{bucket.name}/{gcs_blob_name}"
            
            if public_url:
                return JSONResponse(status_code=200, content={
                    "status": "ok",
                    "data": {
                        "url": public_url,
                        "file_url": public_url
                    }
                })
            else:
                raise HTTPException(500, detail="Failed to upload file to GCS")
                
        except Exception as e:
            logging.error(f"Error uploading file to GCS: {e}")
            raise HTTPException(500, detail=f"Failed to upload file: {str(e)}")
    
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        raise HTTPException(500, detail=str(e))

@router.get("/email/files", description="List uploaded email files")
async def feature_content_email_files(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    folder: str = Query("email", description="Folder name")
):
    try:
        if not property_id:
            raise HTTPException(400, detail="property_id is required")
        
        try:
            # List files from GCS bucket
            client = gcs_storage.Client(project=os.environ.get("GCP_PROJECT"))
            bucket = client.bucket("c360-public-resource")
            
            # Construct prefix path: {property_id}/email/
            prefix = f"{property_id}/{folder}/"
            
            # List all blobs with the prefix
            blobs = bucket.list_blobs(prefix=prefix)
            
            files_list = []
            for blob in blobs:
                # Skip if it's a folder (ends with /)
                if blob.name.endswith('/'):
                    continue
                
                # Get file info
                file_info = {
                    "file_name": os.path.basename(blob.name),
                    "file_path": blob.name,
                    "url": blob.public_url,
                    "file_url": blob.public_url,
                    "content_type": blob.content_type,
                    "size": blob.size,
                    "created": blob.time_created.isoformat() if blob.time_created else None,
                    "updated": blob.updated.isoformat() if blob.updated else None,
                }
                files_list.append(file_info)
            
            # Sort by created time (newest first)
            files_list.sort(key=lambda x: x['created'] if x['created'] else '', reverse=True)
            
            return JSONResponse(status_code=200, content={
                "status": "ok",
                "data": {
                    "files": files_list,
                    "total": len(files_list)
                }
            })
                
        except Exception as e:
            logging.error(f"Error listing files from GCS: {e}")
            raise HTTPException(500, detail=f"Failed to list files: {str(e)}")
    
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        raise HTTPException(500, detail=str(e))

@router.get("/email/channels", description="Get list of email channels")
async def feature_content_email_channels(
    default_request: Request,
    property_id: str = Query(..., description="Property ID")
):
    try:
        # Get all email channels from Firebase
        channels_ref = fb.db.reference().child(f"property/{property_id}/channel/email")
        channels_data = channels_ref.get()
        
        if not channels_data:
            return JSONResponse(status_code=200, content={
                "status": "ok",
                "message": "No email channels found",
                "data": []
            })
        
        # Format channels list
        channels_list = []
        for channel_id, channel_info in channels_data.items():
            if channel_info.get("status") == "active":
                channels_list.append({
                    "id": channel_id,
                    "display_name": channel_info.get("display_name", channel_id),
                    "provider": channel_info.get("provider", "infobip")
                })
        
        return JSONResponse(status_code=200, content={
            "status": "ok",
            "message": "Email channels retrieved successfully",
            "data": channels_list
        })
    except Exception as e:
        logging.error(f"Error getting email channels: {e}")
        raise HTTPException(500, detail=str(e))

@router.post("/email/test", description="Send test email")
async def feature_content_email_test(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    content_id: str = Query(..., description="Email template content ID"),
    channel_id: str = Query(..., description="Email channel ID"),
    to_email: str = Query(..., description="Recipient email address")
):
    try:
        from .email_sender import send_test_email
        
        # Validate email format
        email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        if not re.match(email_pattern, to_email):
            raise HTTPException(400, detail="Invalid email address format")
        
        # Send test email
        result = send_test_email(property_id, content_id, channel_id, to_email)
        
        if result.get("success"):
            return JSONResponse(status_code=200, content={
                "status": "ok",
                "message": result.get("message", "Test email sent successfully"),
                "data": result
            })
        else:
            return JSONResponse(status_code=400, content={
                "status": "error",
                "message": result.get("error", "Failed to send test email"),
                "data": result
            })
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error sending test email: {e}")
        raise HTTPException(500, detail=str(e))

@router.get("/sms/channels", description="Get list of SMS channels")
async def feature_content_sms_channels(
    default_request: Request,
    property_id: str = Query(..., description="Property ID")
):
    try:
        # Get all SMS channels from Firebase
        channels_ref = fb.db.reference().child(f"property/{property_id}/channel/sms")
        channels_data = channels_ref.get()
        
        if not channels_data:
            return JSONResponse(status_code=200, content={
                "status": "ok",
                "message": "No SMS channels found",
                "data": []
            })
        
        # Format channels list
        channels_list = []
        for channel_id, channel_info in channels_data.items():
            if channel_info.get("status") == "active":
                channels_list.append({
                    "id": channel_id,
                    "display_name": channel_info.get("display_name", channel_id),
                    "provider": channel_info.get("provider", "infobip")
                })
        
        return JSONResponse(status_code=200, content={
            "status": "ok",
            "message": "SMS channels retrieved successfully",
            "data": channels_list
        })
    except Exception as e:
        logging.error(f"Error getting SMS channels: {e}")
        raise HTTPException(500, detail=str(e))

@router.post("/sms/test", description="Send test SMS")
async def feature_content_sms_test(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    content_id: str = Query(..., description="SMS template content ID"),
    channel_id: str = Query(..., description="SMS channel ID"),
    to_phone: str = Query(..., description="Recipient phone number")
):
    try:
        from .sms_sender import send_test_sms
        
        # Validate phone number format (Thai format: 0XXXXXXXXX or +66XXXXXXXXX)
        import re
        phone_pattern = r'^(\+66|0)[0-9]{9}$'
        if not re.match(phone_pattern, to_phone):
            raise HTTPException(400, detail="Invalid phone number format. Use 0XXXXXXXXX or +66XXXXXXXXX")
        
        # Send test SMS
        result = send_test_sms(property_id, content_id, channel_id, to_phone)
        
        if result.get("success"):
            return JSONResponse(status_code=200, content={
                "status": "ok",
                "message": result.get("message", "Test SMS sent successfully"),
                "data": result
            })
        else:
            return JSONResponse(status_code=400, content={
                "status": "error",
                "message": result.get("error", "Failed to send test SMS"),
                "data": result
            })
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error sending test SMS: {e}")
        raise HTTPException(500, detail=str(e))
