from fastapi import Request, Query, Depends, APIRouter, HTTPException
from fastapi.responses import JSONResponse
from utility.function import Function
from connectors.firebase.firebase import Firebase
import pytz
import os
from datetime import datetime
from typing import Optional, List, Literal, Tuple
from models.settings import *

import logging
logging.basicConfig(level=logging.INFO)

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

LOGGING_PREFIX = "api_settings_senders"
timezone = pytz.timezone("Asia/Bangkok")

SMS_TYPE_CHOICES = {"alphanumeric", "long_number", "short_code"}
STATUS_CHOICES = {"active", "inactive"}

# SMS searchable fields
SMS_SEARCHABLE_FIELDS = ["display_name", "sender_value", "provider", "type", "status", "country"]
# Email searchable fields
EMAIL_SEARCHABLE_FIELDS = ["display_name", "from_email", "from_name", "provider", "status", "domain"]

def _now_iso():
    return datetime.now(timezone).isoformat()

def _sms_ref(property_id):
    return fb.db.reference().child(f"account/{property_id}/Senders/SMS")

def _email_ref(property_id):
    return fb.db.reference().child(f"account/{property_id}/Senders/Email")

def _list_response(ref):
    """Get all senders from Firebase reference"""
    raw = ref.get()
    if not raw:
        return []
    result = []
    for sender_id, payload in raw.items():
        item = payload or {}
        item["id"] = sender_id
        result.append(item)
    return result

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

# SMS Senders Endpoints
@router.get("/sms-senders", description="Get SMS senders list with pagination and filter")
async def get_sms_senders(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    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:
        # Get all senders
        senders = _list_response(_sms_ref(property_id))
        
        # Apply filters
        if filter:
            senders = _apply_filters(senders, filter)
        
        # Apply sorting
        if sort_by:
            senders = _apply_sort(senders, sort_by, order)
        
        # Apply pagination
        items, pagination = _apply_pagination(senders, offset, limit)
        
        # Return response with pagination format (always return pagination format when offset/limit are provided)
        # Since offset and limit have default values, we always return pagination format
        return JSONResponse(status_code=200, content={
            "status": "ok",
            "message": "SMS senders retrieved successfully",
            "data": {
                "items": items,
                "pagination": pagination
            }
        })
    except Exception as e:
        logging.error(f"Error {LOGGING_PREFIX}_get_sms_senders: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/sms-senders", description="Create a new SMS sender")
async def create_sms_sender(default_request: Request, request: CreateSMSSender):
    try:
        # Validate type
        if request.type not in SMS_TYPE_CHOICES:
            raise HTTPException(400, detail=f"type must be one of {', '.join(SMS_TYPE_CHOICES)}")
        
        # Validate status
        if request.status not in STATUS_CHOICES:
            raise HTTPException(400, detail=f"status must be one of {', '.join(STATUS_CHOICES)}")
        
        # Check if sender already exists
        ref = _sms_ref(request.property_id).child(request.id)
        if ref.get():
            raise HTTPException(400, detail="id already exists")
        
        # Create record
        now_iso = _now_iso()
        record = {
            "id": request.id,
            "channel": "sms",
            "provider": request.provider,
            "display_name": request.display_name,
            "sender_value": request.sender_value,
            "country": request.country,
            "type": request.type,
            "provider_account_id": request.provider_account_id,
            "status": request.status,
            "created_at": now_iso,
            "updated_at": now_iso,
        }
        ref.set(record)
        
        return JSONResponse(status_code=201, content={
            "status": "ok",
            "message": "SMS sender created successfully",
            "data": record
        })
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error {LOGGING_PREFIX}_create_sms_sender: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@router.put("/sms-senders/{sender_id}", description="Update an existing SMS sender")
async def update_sms_sender(
    default_request: Request,
    sender_id: str,
    request: UpdateSMSSender
):
    try:
        ref = _sms_ref(request.property_id).child(sender_id)
        existing = ref.get()
        if not existing:
            raise HTTPException(404, detail="SMS sender not found")
        
        # Validate type if provided
        if request.type and request.type not in SMS_TYPE_CHOICES:
            raise HTTPException(400, detail=f"type must be one of {', '.join(SMS_TYPE_CHOICES)}")
        
        # Validate status if provided
        if request.status and request.status not in STATUS_CHOICES:
            raise HTTPException(400, detail=f"status must be one of {', '.join(STATUS_CHOICES)}")
        
        # Update only provided fields
        update_data = request.model_dump(exclude={"property_id"}, exclude_none=True)
        if "id" in update_data:
            del update_data["id"]  # Don't allow changing ID
        
        now_iso = _now_iso()
        update_data["updated_at"] = now_iso
        
        # Merge with existing data
        for key, value in update_data.items():
            ref.child(key).set(value)
        
        # Get updated record
        updated = ref.get()
        updated["id"] = sender_id
        
        return JSONResponse(status_code=200, content={
            "status": "ok",
            "message": "SMS sender updated successfully",
            "data": updated
        })
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error {LOGGING_PREFIX}_update_sms_sender: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@router.delete("/sms-senders/{sender_id}", description="Delete an SMS sender")
async def delete_sms_sender(
    default_request: Request,
    sender_id: str,
    property_id: str = Query(..., description="Property ID")
):
    try:
        ref = _sms_ref(property_id).child(sender_id)
        existing = ref.get()
        if not existing:
            raise HTTPException(404, detail="SMS sender not found")
        
        ref.delete()
        
        return JSONResponse(status_code=200, content={
            "status": "ok",
            "message": "SMS sender deleted successfully",
            "data": existing
        })
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error {LOGGING_PREFIX}_delete_sms_sender: {e}")
        raise HTTPException(status_code=500, detail=str(e))

# Email Senders Endpoints
@router.get("/email-senders", description="Get Email senders list with pagination and filter")
async def get_email_senders(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    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:
        # Get all senders
        senders = _list_response(_email_ref(property_id))
        
        # Apply filters
        if filter:
            senders = _apply_filters(senders, filter)
        
        # Apply sorting
        if sort_by:
            senders = _apply_sort(senders, sort_by, order)
        
        # Apply pagination
        items, pagination = _apply_pagination(senders, offset, limit)
        
        # Return response with pagination format (always return pagination format when offset/limit are provided)
        # Since offset and limit have default values, we always return pagination format
        return JSONResponse(status_code=200, content={
            "status": "ok",
            "message": "Email senders retrieved successfully",
            "data": {
                "items": items,
                "pagination": pagination
            }
        })
    except Exception as e:
        logging.error(f"Error {LOGGING_PREFIX}_get_email_senders: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/email-senders", description="Create a new Email sender")
async def create_email_sender(default_request: Request, request: CreateEmailSender):
    try:
        # Validate status
        if request.status not in STATUS_CHOICES:
            raise HTTPException(400, detail=f"status must be one of {', '.join(STATUS_CHOICES)}")
        
        # Check if sender already exists
        ref = _email_ref(request.property_id).child(request.id)
        if ref.get():
            raise HTTPException(400, detail="id already exists")
        
        # Create record
        now_iso = _now_iso()
        record = {
            "id": request.id,
            "channel": "email",
            "provider": request.provider,
            "display_name": request.display_name,
            "from_email": request.from_email,
            "from_name": request.from_name,
            "reply_to_email": request.reply_to_email,
            "domain": request.domain,
            "provider_account_id": request.provider_account_id,
            "status": request.status,
            "created_at": now_iso,
            "updated_at": now_iso,
        }
        ref.set(record)
        
        return JSONResponse(status_code=201, content={
            "status": "ok",
            "message": "Email sender created successfully",
            "data": record
        })
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error {LOGGING_PREFIX}_create_email_sender: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@router.put("/email-senders/{sender_id}", description="Update an existing Email sender")
async def update_email_sender(
    default_request: Request,
    sender_id: str,
    request: UpdateEmailSender
):
    try:
        ref = _email_ref(request.property_id).child(sender_id)
        existing = ref.get()
        if not existing:
            raise HTTPException(404, detail="Email sender not found")
        
        # Validate status if provided
        if request.status and request.status not in STATUS_CHOICES:
            raise HTTPException(400, detail=f"status must be one of {', '.join(STATUS_CHOICES)}")
        
        # Update only provided fields
        update_data = request.model_dump(exclude={"property_id"}, exclude_none=True)
        if "id" in update_data:
            del update_data["id"]  # Don't allow changing ID
        
        now_iso = _now_iso()
        update_data["updated_at"] = now_iso
        
        # Merge with existing data
        for key, value in update_data.items():
            ref.child(key).set(value)
        
        # Get updated record
        updated = ref.get()
        updated["id"] = sender_id
        
        return JSONResponse(status_code=200, content={
            "status": "ok",
            "message": "Email sender updated successfully",
            "data": updated
        })
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error {LOGGING_PREFIX}_update_email_sender: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@router.delete("/email-senders/{sender_id}", description="Delete an Email sender")
async def delete_email_sender(
    default_request: Request,
    sender_id: str,
    property_id: str = Query(..., description="Property ID")
):
    try:
        ref = _email_ref(property_id).child(sender_id)
        existing = ref.get()
        if not existing:
            raise HTTPException(404, detail="Email sender not found")
        
        ref.delete()
        
        return JSONResponse(status_code=200, content={
            "status": "ok",
            "message": "Email sender deleted successfully",
            "data": existing
        })
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error {LOGGING_PREFIX}_delete_email_sender: {e}")
        raise HTTPException(status_code=500, detail=str(e))
