from fastapi import APIRouter, Depends, HTTPException, status, Request, UploadFile, File, Form
from sqlalchemy.orm import Session
from typing import Optional
from datetime import datetime
from pydantic import BaseModel, EmailStr
from pathlib import Path
import logging
import aiofiles
import uuid
import os

from ...shared.config.database import get_db
from ...security.middleware.auth import get_current_user, authorize_roles
from ...auth.models.user import User
from ..models.system_settings import SystemSettings
from ...shared.utils.mailer import send_email
from ...rooms.services.room_service import get_base_url
from ...analytics.services.audit_service import audit_service
from ...payments.services.financial_audit_service import financial_audit_service
from ...payments.models.financial_audit_trail import FinancialActionType

def normalize_image_url(image_url: str, base_url: str) -> str:
    if not image_url:
        return image_url
    if image_url.startswith('http://') or image_url.startswith('https://'):
        return image_url
    if image_url.startswith('/'):
        return f"{base_url}{image_url}"
    return f"{base_url}/{image_url}"

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/admin/system-settings", tags=["admin-system-settings"])

@router.get("/currency")
async def get_platform_currency(
    db: Session = Depends(get_db)
):
    try:
        setting = db.query(SystemSettings).filter(
            SystemSettings.key == "platform_currency"
        ).first()
        
        if not setting:

            return {
                "status": "success",
                "data": {
                    "currency": "VND",
                    "updated_at": None,
                    "updated_by": None
                }
            }
        
        return {
            "status": "success",
            "data": {
                "currency": setting.value,
                "updated_at": setting.updated_at.isoformat() if setting.updated_at else None,
                "updated_by": setting.updated_by.full_name if setting.updated_by else None
            }
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.put("/currency")
async def update_platform_currency(
    currency_data: dict,
    request: Request,
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    
    try:
        currency = currency_data.get("currency", "").upper()
        

        if not currency or len(currency) != 3 or not currency.isalpha():
            raise HTTPException(
                status_code=400,
                detail="Invalid currency code. Must be a 3-letter ISO 4217 code (e.g., USD, EUR, VND)"
            )
        

        setting = db.query(SystemSettings).filter(
            SystemSettings.key == "platform_currency"
        ).first()
        
        old_value = setting.value if setting else None
        
        if setting:
            setting.value = currency
            setting.updated_by_id = current_user.id
        else:
            setting = SystemSettings(
                key="platform_currency",
                value=currency,
                description="Platform-wide currency setting for displaying prices across the application",
                updated_by_id=current_user.id
            )
            db.add(setting)
        
        db.commit()
        db.refresh(setting)
        
        # SECURITY: Log system setting change for audit trail
        try:
            await audit_service.log_action(
                db=db,
                action='system_setting_changed',
                resource_type='system_settings',
                user_id=current_user.id,
                resource_id=setting.id,
                ip_address=client_ip,
                user_agent=user_agent,
                request_id=request_id,
                details={
                    'setting_key': 'platform_currency',
                    'old_value': old_value,
                    'new_value': currency
                },
                status='success'
            )
            # Also log to financial audit trail (currency affects financial reporting)
            try:
                financial_audit_service.log_financial_action(
                    db=db,
                    action_type=FinancialActionType.settings_changed,
                    performed_by=current_user.id,
                    action_description=f'Platform currency changed from {old_value} to {currency}',
                    currency=currency,
                    metadata={
                        'setting_key': 'platform_currency',
                        'old_value': old_value,
                        'new_value': currency,
                        'ip_address': client_ip,
                        'user_agent': user_agent,
                        'request_id': request_id
                    },
                    notes=f'Currency setting updated by {current_user.email}'
                )
            except Exception as e:
                logger.warning(f'Failed to log financial audit for currency change: {e}')
        except Exception as e:
            logger.warning(f'Failed to log system setting change audit: {e}')
        
        return {
            "status": "success",
            "message": "Platform currency updated successfully",
            "data": {
                "currency": setting.value,
                "updated_at": setting.updated_at.isoformat() if setting.updated_at else None,
                "updated_by": setting.updated_by.full_name if setting.updated_by else None
            }
        }
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/")
async def get_all_settings(
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    try:
        settings = db.query(SystemSettings).all()
        
        result = []
        for setting in settings:
            result.append({
                "key": setting.key,
                "value": setting.value,
                "description": setting.description,
                "updated_at": setting.updated_at.isoformat() if setting.updated_at else None,
                "updated_by": setting.updated_by.full_name if setting.updated_by else None
            })
        
        return {
            "status": "success",
            "data": {
                "settings": result
            }
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/stripe")
async def get_stripe_settings(
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    try:
        secret_key_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "stripe_secret_key"
        ).first()
        
        publishable_key_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "stripe_publishable_key"
        ).first()
        
        webhook_secret_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "stripe_webhook_secret"
        ).first()
        

        def mask_key(key_value: str) -> str:
            if not key_value or len(key_value) < 4:
                return ""
            return "*" * (len(key_value) - 4) + key_value[-4:]
        
        result = {
            "stripe_secret_key": "",
            "stripe_publishable_key": "",
            "stripe_webhook_secret": "",
            "stripe_secret_key_masked": "",
            "stripe_webhook_secret_masked": "",
            "has_secret_key": False,
            "has_publishable_key": False,
            "has_webhook_secret": False,
        }
        
        if secret_key_setting:
            result["stripe_secret_key"] = secret_key_setting.value
            result["stripe_secret_key_masked"] = mask_key(secret_key_setting.value)
            result["has_secret_key"] = bool(secret_key_setting.value)
            result["updated_at"] = secret_key_setting.updated_at.isoformat() if secret_key_setting.updated_at else None
            result["updated_by"] = secret_key_setting.updated_by.full_name if secret_key_setting.updated_by else None
        
        if publishable_key_setting:
            result["stripe_publishable_key"] = publishable_key_setting.value
            result["has_publishable_key"] = bool(publishable_key_setting.value)
        
        if webhook_secret_setting:
            result["stripe_webhook_secret"] = webhook_secret_setting.value
            result["stripe_webhook_secret_masked"] = mask_key(webhook_secret_setting.value)
            result["has_webhook_secret"] = bool(webhook_secret_setting.value)
        
        return {
            "status": "success",
            "data": result
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.put("/stripe")
async def update_stripe_settings(
    stripe_data: dict,
    request: Request,
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    try:
        secret_key = stripe_data.get("stripe_secret_key", "").strip()
        publishable_key = stripe_data.get("stripe_publishable_key", "").strip()
        webhook_secret = stripe_data.get("stripe_webhook_secret", "").strip()
        

        if secret_key and not secret_key.startswith("sk_"):
            raise HTTPException(
                status_code=400,
                detail="Invalid Stripe secret key format. Must start with 'sk_'"
            )
        

        if publishable_key and not publishable_key.startswith("pk_"):
            raise HTTPException(
                status_code=400,
                detail="Invalid Stripe publishable key format. Must start with 'pk_'"
            )
        

        if webhook_secret and not webhook_secret.startswith("whsec_"):
            raise HTTPException(
                status_code=400,
                detail="Invalid Stripe webhook secret format. Must start with 'whsec_'"
            )
        

        settings_changed = []
        old_values = {}
        
        if secret_key:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "stripe_secret_key"
            ).first()
            
            old_values['stripe_secret_key'] = setting.value if setting else None
            
            if setting:
                setting.value = secret_key
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="stripe_secret_key",
                    value=secret_key,
                    description="Stripe secret key for processing payments",
                    updated_by_id=current_user.id
                )
                db.add(setting)
            settings_changed.append('stripe_secret_key')
        

        if publishable_key:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "stripe_publishable_key"
            ).first()
            
            old_values['stripe_publishable_key'] = setting.value if setting else None
            
            if setting:
                setting.value = publishable_key
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="stripe_publishable_key",
                    value=publishable_key,
                    description="Stripe publishable key for frontend payment forms",
                    updated_by_id=current_user.id
                )
                db.add(setting)
            settings_changed.append('stripe_publishable_key')
        

        if webhook_secret:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "stripe_webhook_secret"
            ).first()
            
            old_values['stripe_webhook_secret'] = setting.value if setting else None
            
            if setting:
                setting.value = webhook_secret
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="stripe_webhook_secret",
                    value=webhook_secret,
                    description="Stripe webhook secret for verifying webhook events",
                    updated_by_id=current_user.id
                )
                db.add(setting)
            settings_changed.append('stripe_webhook_secret')
        
        db.commit()
        
        # SECURITY: Log payment gateway configuration change for audit trail
        if settings_changed:
            try:
                def mask_key(key_value: str) -> str:
                    if not key_value or len(key_value) < 4:
                        return None
                    return "*" * (len(key_value) - 4) + key_value[-4:]
                
                masked_old = {k: mask_key(v) if v else None for k, v in old_values.items() if k in settings_changed}
                masked_new = {k: mask_key(v) if v else None for k, v in {
                    'stripe_secret_key': secret_key if secret_key else None,
                    'stripe_publishable_key': publishable_key if publishable_key else None,
                    'stripe_webhook_secret': webhook_secret if webhook_secret else None
                }.items() if k in settings_changed}
                
                await audit_service.log_action(
                    db=db,
                    action='payment_gateway_config_changed',
                    resource_type='system_settings',
                    user_id=current_user.id,
                    resource_id=None,
                    ip_address=client_ip,
                    user_agent=user_agent,
                    request_id=request_id,
                    details={
                        'gateway': 'stripe',
                        'settings_changed': settings_changed,
                        'old_values': masked_old,
                        'new_values': masked_new
                    },
                    status='success'
                )
            except Exception as e:
                logger.warning(f'Failed to log payment gateway config change audit: {e}')

        def mask_key(key_value: str) -> str:
            if not key_value or len(key_value) < 4:
                return ""
            return "*" * (len(key_value) - 4) + key_value[-4:]
        
        return {
            "status": "success",
            "message": "Stripe settings updated successfully",
            "data": {
                "stripe_secret_key": secret_key if secret_key else "",
                "stripe_publishable_key": publishable_key,
                "stripe_webhook_secret": webhook_secret if webhook_secret else "",
                "stripe_secret_key_masked": mask_key(secret_key) if secret_key else "",
                "stripe_webhook_secret_masked": mask_key(webhook_secret) if webhook_secret else "",
                "has_secret_key": bool(secret_key),
                "has_publishable_key": bool(publishable_key),
                "has_webhook_secret": bool(webhook_secret),
            }
        }
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/paypal")
async def get_paypal_settings(
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    try:
        client_id_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "paypal_client_id"
        ).first()
        
        client_secret_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "paypal_client_secret"
        ).first()
        
        mode_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "paypal_mode"
        ).first()
        

        def mask_key(key_value: str) -> str:
            if not key_value or len(key_value) < 4:
                return ""
            return "*" * (len(key_value) - 4) + key_value[-4:]
        
        result = {
            "paypal_client_id": "",
            "paypal_client_secret": "",
            "paypal_mode": "sandbox",
            "paypal_client_secret_masked": "",
            "has_client_id": False,
            "has_client_secret": False,
        }
        
        if client_id_setting:
            result["paypal_client_id"] = client_id_setting.value
            result["has_client_id"] = bool(client_id_setting.value)
            result["updated_at"] = client_id_setting.updated_at.isoformat() if client_id_setting.updated_at else None
            result["updated_by"] = client_id_setting.updated_by.full_name if client_id_setting.updated_by else None
        
        if client_secret_setting:
            result["paypal_client_secret"] = client_secret_setting.value
            result["paypal_client_secret_masked"] = mask_key(client_secret_setting.value)
            result["has_client_secret"] = bool(client_secret_setting.value)
        
        if mode_setting:
            result["paypal_mode"] = mode_setting.value or "sandbox"
        
        return {
            "status": "success",
            "data": result
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.put("/paypal")
async def update_paypal_settings(
    paypal_data: dict,
    request: Request,
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    
    try:
        client_id = paypal_data.get("paypal_client_id", "").strip()
        client_secret = paypal_data.get("paypal_client_secret", "").strip()
        mode = paypal_data.get("paypal_mode", "sandbox").strip().lower()
        

        if mode and mode not in ["sandbox", "live"]:
            raise HTTPException(
                status_code=400,
                detail="Invalid PayPal mode. Must be 'sandbox' or 'live'"
            )
        
        settings_changed = []
        old_values = {}
        
        # Get old values before updating
        if client_id:
            old_setting = db.query(SystemSettings).filter(SystemSettings.key == "paypal_client_id").first()
            old_values['paypal_client_id'] = old_setting.value if old_setting else None
        
        if client_secret:
            old_setting = db.query(SystemSettings).filter(SystemSettings.key == "paypal_client_secret").first()
            old_values['paypal_client_secret'] = old_setting.value if old_setting else None
        
        if mode:
            old_setting = db.query(SystemSettings).filter(SystemSettings.key == "paypal_mode").first()
            old_values['paypal_mode'] = old_setting.value if old_setting else None

        if client_id:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "paypal_client_id"
            ).first()
            
            if setting:
                setting.value = client_id
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="paypal_client_id",
                    value=client_id,
                    description="PayPal client ID for processing payments",
                    updated_by_id=current_user.id
                )
                db.add(setting)
            settings_changed.append('paypal_client_id')
        

        if client_secret:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "paypal_client_secret"
            ).first()
            
            if setting:
                setting.value = client_secret
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="paypal_client_secret",
                    value=client_secret,
                    description="PayPal client secret for processing payments",
                    updated_by_id=current_user.id
                )
                db.add(setting)
            settings_changed.append('paypal_client_secret')
        

        if mode:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "paypal_mode"
            ).first()
            
            if setting:
                setting.value = mode
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="paypal_mode",
                    value=mode,
                    description="PayPal mode: sandbox or live",
                    updated_by_id=current_user.id
                )
                db.add(setting)
            settings_changed.append('paypal_mode')
        
        db.commit()
        
        # SECURITY: Log payment gateway configuration change for audit trail
        if settings_changed:
            try:
                def mask_key(key_value: str) -> str:
                    if not key_value or len(key_value) < 4:
                        return None
                    return "*" * (len(key_value) - 4) + key_value[-4:]
                
                masked_old = {k: mask_key(v) if v else None for k, v in old_values.items() if k in settings_changed}
                masked_new = {k: mask_key(v) if v else None for k, v in {
                    'paypal_client_id': client_id if client_id else None,
                    'paypal_client_secret': client_secret if client_secret else None,
                    'paypal_mode': mode if mode else None
                }.items() if k in settings_changed}
                
                await audit_service.log_action(
                    db=db,
                    action='payment_gateway_config_changed',
                    resource_type='system_settings',
                    user_id=current_user.id,
                    resource_id=None,
                    ip_address=client_ip,
                    user_agent=user_agent,
                    request_id=request_id,
                    details={
                        'gateway': 'paypal',
                        'settings_changed': settings_changed,
                        'old_values': masked_old,
                        'new_values': masked_new
                    },
                    status='success'
                )
            except Exception as e:
                logger.warning(f'Failed to log payment gateway config change audit: {e}')

        def mask_key(key_value: str) -> str:
            if not key_value or len(key_value) < 4:
                return ""
            return "*" * (len(key_value) - 4) + key_value[-4:]
        
        return {
            "status": "success",
            "message": "PayPal settings updated successfully",
            "data": {
                "paypal_client_id": client_id if client_id else "",
                "paypal_client_secret": client_secret if client_secret else "",
                "paypal_mode": mode,
                "paypal_client_secret_masked": mask_key(client_secret) if client_secret else "",
                "has_client_id": bool(client_id),
                "has_client_secret": bool(client_secret),
            }
        }
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/borica")
async def get_borica_settings(
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    try:
        terminal_id_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "borica_terminal_id"
        ).first()
        
        merchant_id_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "borica_merchant_id"
        ).first()
        
        private_key_path_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "borica_private_key_path"
        ).first()
        
        certificate_path_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "borica_certificate_path"
        ).first()
        
        gateway_url_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "borica_gateway_url"
        ).first()
        
        mode_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "borica_mode"
        ).first()
        
        def mask_key(key_value: str) -> str:
            if not key_value or len(key_value) < 4:
                return ""
            return "*" * (len(key_value) - 4) + key_value[-4:]
        
        result = {
            "borica_terminal_id": "",
            "borica_merchant_id": "",
            "borica_private_key_path": "",
            "borica_certificate_path": "",
            "borica_gateway_url": "",
            "borica_mode": "test",
            "borica_terminal_id_masked": "",
            "borica_merchant_id_masked": "",
            "has_terminal_id": False,
            "has_merchant_id": False,
            "has_private_key_path": False,
            "has_certificate_path": False,
        }
        
        if terminal_id_setting:
            result["borica_terminal_id"] = terminal_id_setting.value
            result["borica_terminal_id_masked"] = mask_key(terminal_id_setting.value) if terminal_id_setting.value else ""
            result["has_terminal_id"] = bool(terminal_id_setting.value)
            result["updated_at"] = terminal_id_setting.updated_at.isoformat() if terminal_id_setting.updated_at else None
            result["updated_by"] = terminal_id_setting.updated_by.full_name if terminal_id_setting.updated_by else None
        
        if merchant_id_setting:
            result["borica_merchant_id"] = merchant_id_setting.value
            result["borica_merchant_id_masked"] = mask_key(merchant_id_setting.value) if merchant_id_setting.value else ""
            result["has_merchant_id"] = bool(merchant_id_setting.value)
        
        if private_key_path_setting:
            result["borica_private_key_path"] = private_key_path_setting.value
            result["has_private_key_path"] = bool(private_key_path_setting.value)
        
        if certificate_path_setting:
            result["borica_certificate_path"] = certificate_path_setting.value
            result["has_certificate_path"] = bool(certificate_path_setting.value)
        
        if gateway_url_setting:
            result["borica_gateway_url"] = gateway_url_setting.value or ""
        
        if mode_setting:
            result["borica_mode"] = mode_setting.value or "test"
        
        return {
            "status": "success",
            "data": result
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.put("/borica")
async def update_borica_settings(
    borica_data: dict,
    request: Request,
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    
    try:
        terminal_id = borica_data.get("borica_terminal_id", "").strip()
        merchant_id = borica_data.get("borica_merchant_id", "").strip()
        private_key_path = borica_data.get("borica_private_key_path", "").strip()
        certificate_path = borica_data.get("borica_certificate_path", "").strip()
        gateway_url = borica_data.get("borica_gateway_url", "").strip()
        mode = borica_data.get("borica_mode", "test").strip().lower()
        
        if mode and mode not in ["test", "production"]:
            raise HTTPException(
                status_code=400,
                detail="Invalid Borica mode. Must be 'test' or 'production'"
            )
        
        settings_changed = []
        old_values = {}
        
        # Get old values before updating
        if terminal_id:
            old_setting = db.query(SystemSettings).filter(SystemSettings.key == "borica_terminal_id").first()
            old_values['borica_terminal_id'] = old_setting.value if old_setting else None
        if merchant_id:
            old_setting = db.query(SystemSettings).filter(SystemSettings.key == "borica_merchant_id").first()
            old_values['borica_merchant_id'] = old_setting.value if old_setting else None
        if mode:
            old_setting = db.query(SystemSettings).filter(SystemSettings.key == "borica_mode").first()
            old_values['borica_mode'] = old_setting.value if old_setting else None
        
        if terminal_id:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "borica_terminal_id"
            ).first()
            
            if setting:
                setting.value = terminal_id
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="borica_terminal_id",
                    value=terminal_id,
                    description="Borica Terminal ID for processing payments",
                    updated_by_id=current_user.id
                )
                db.add(setting)
        
        if merchant_id:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "borica_merchant_id"
            ).first()
            
            if setting:
                setting.value = merchant_id
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="borica_merchant_id",
                    value=merchant_id,
                    description="Borica Merchant ID for processing payments",
                    updated_by_id=current_user.id
                )
                db.add(setting)
        
        if private_key_path:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "borica_private_key_path"
            ).first()
            
            if setting:
                setting.value = private_key_path
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="borica_private_key_path",
                    value=private_key_path,
                    description="Path to Borica private key file",
                    updated_by_id=current_user.id
                )
                db.add(setting)
        
        if certificate_path:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "borica_certificate_path"
            ).first()
            
            if setting:
                setting.value = certificate_path
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="borica_certificate_path",
                    value=certificate_path,
                    description="Path to Borica certificate file",
                    updated_by_id=current_user.id
                )
                db.add(setting)
        
        if gateway_url:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "borica_gateway_url"
            ).first()
            
            if setting:
                setting.value = gateway_url
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="borica_gateway_url",
                    value=gateway_url,
                    description="Borica gateway URL (test or production)",
                    updated_by_id=current_user.id
                )
                db.add(setting)
        
        if mode:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "borica_mode"
            ).first()
            
            if setting:
                setting.value = mode
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="borica_mode",
                    value=mode,
                    description="Borica mode: test or production",
                    updated_by_id=current_user.id
                )
                db.add(setting)
        
        db.commit()
        
        def mask_key(key_value: str) -> str:
            if not key_value or len(key_value) < 4:
                return ""
            return "*" * (len(key_value) - 4) + key_value[-4:]
        
        return {
            "status": "success",
            "message": "Borica settings updated successfully",
            "data": {
                "borica_terminal_id": terminal_id if terminal_id else "",
                "borica_merchant_id": merchant_id if merchant_id else "",
                "borica_private_key_path": private_key_path if private_key_path else "",
                "borica_certificate_path": certificate_path if certificate_path else "",
                "borica_gateway_url": gateway_url if gateway_url else "",
                "borica_mode": mode,
                "borica_terminal_id_masked": mask_key(terminal_id) if terminal_id else "",
                "borica_merchant_id_masked": mask_key(merchant_id) if merchant_id else "",
                "has_terminal_id": bool(terminal_id),
                "has_merchant_id": bool(merchant_id),
                "has_private_key_path": bool(private_key_path),
                "has_certificate_path": bool(certificate_path),
            }
        }
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/borica/upload-certificate")
async def upload_borica_certificate(
    file: UploadFile = File(...),
    file_type: str = Form("private_key"),  # "private_key" or "certificate"
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    """
    Upload Borica certificate or private key file.
    file_type: "private_key" or "certificate"
    """
    try:
        if not file:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="No file provided"
            )
        
        if not file.filename:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Filename is required"
            )
        
        # Validate file type
        allowed_extensions = ['.pem', '.key', '.crt', '.cer', '.p12', '.pfx']
        file_ext = Path(file.filename).suffix.lower()
        
        if file_ext not in allowed_extensions:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Invalid file type. Allowed extensions: {', '.join(allowed_extensions)}"
            )
        
        # Validate file_type parameter
        if file_type not in ["private_key", "certificate"]:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="file_type must be 'private_key' or 'certificate'"
            )
        
        # Create upload directory
        upload_dir = Path(__file__).parent.parent.parent.parent / "uploads" / "certificates" / "borica"
        upload_dir.mkdir(parents=True, exist_ok=True)
        
        # Generate unique filename
        file_type_prefix = "private_key" if file_type == "private_key" else "certificate"
        filename = f"borica_{file_type_prefix}_{uuid.uuid4()}{file_ext}"
        file_path = upload_dir / filename
        
        # Read and save file
        content = await file.read()
        if not content:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="File is empty"
            )
        
        # Validate file size (max 1MB for certificate files)
        max_size = 1024 * 1024  # 1MB
        if len(content) > max_size:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"File size exceeds maximum allowed size of {max_size / 1024}KB"
            )
        
        # Save file
        async with aiofiles.open(file_path, 'wb') as f:
            await f.write(content)
        
        # Get absolute path
        absolute_path = str(file_path.resolve())
        
        # Update system settings with the new path
        setting_key = "borica_private_key_path" if file_type == "private_key" else "borica_certificate_path"
        
        # Delete old file if exists
        old_setting = db.query(SystemSettings).filter(
            SystemSettings.key == setting_key
        ).first()
        
        if old_setting and old_setting.value:
            old_file_path = Path(old_setting.value)
            # Only delete if it's in our uploads directory (safety check)
            if old_file_path.exists() and str(old_file_path).startswith(str(upload_dir)):
                try:
                    old_file_path.unlink()
                except Exception as e:
                    logger.warning(f"Could not delete old file {old_setting.value}: {e}")
        
        # Update or create setting
        if old_setting:
            old_setting.value = absolute_path
            old_setting.updated_by_id = current_user.id
        else:
            setting = SystemSettings(
                key=setting_key,
                value=absolute_path,
                description=f"Path to Borica {file_type.replace('_', ' ')} file",
                updated_by_id=current_user.id
            )
            db.add(setting)
        
        db.commit()
        
        return {
            "status": "success",
            "message": f"Borica {file_type.replace('_', ' ')} uploaded successfully",
            "data": {
                "file_path": absolute_path,
                "file_type": file_type,
                "filename": filename
            }
        }
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f"Error uploading Borica certificate: {e}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error uploading file: {str(e)}"
        )

@router.get("/smtp")
async def get_smtp_settings(
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    try:

        smtp_settings = {}
        setting_keys = [
            "smtp_host",
            "smtp_port",
            "smtp_user",
            "smtp_password",
            "smtp_from_email",
            "smtp_from_name",
            "smtp_use_tls",
        ]
        
        for key in setting_keys:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == key
            ).first()
            if setting:
                smtp_settings[key] = setting.value
        

        def mask_password(password_value: str) -> str:
            if not password_value or len(password_value) < 4:
                return ""
            return "*" * (len(password_value) - 4) + password_value[-4:]
        
        result = {
            "smtp_host": smtp_settings.get("smtp_host", ""),
            "smtp_port": smtp_settings.get("smtp_port", ""),
            "smtp_user": smtp_settings.get("smtp_user", ""),
            "smtp_password": "",
            "smtp_password_masked": mask_password(smtp_settings.get("smtp_password", "")),
            "smtp_from_email": smtp_settings.get("smtp_from_email", ""),
            "smtp_from_name": smtp_settings.get("smtp_from_name", ""),
            "smtp_use_tls": smtp_settings.get("smtp_use_tls", "true").lower() == "true",
            "has_host": bool(smtp_settings.get("smtp_host")),
            "has_user": bool(smtp_settings.get("smtp_user")),
            "has_password": bool(smtp_settings.get("smtp_password")),
        }
        

        password_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "smtp_password"
        ).first()
        
        if password_setting:
            result["updated_at"] = password_setting.updated_at.isoformat() if password_setting.updated_at else None
            result["updated_by"] = password_setting.updated_by.full_name if password_setting.updated_by else None
        else:

            any_setting = db.query(SystemSettings).filter(
                SystemSettings.key.in_(setting_keys)
            ).first()
            if any_setting:
                result["updated_at"] = any_setting.updated_at.isoformat() if any_setting.updated_at else None
                result["updated_by"] = any_setting.updated_by.full_name if any_setting.updated_by else None
            else:
                result["updated_at"] = None
                result["updated_by"] = None
        
        return {
            "status": "success",
            "data": result
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.put("/smtp")
async def update_smtp_settings(
    smtp_data: dict,
    request: Request,
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    
    try:
        smtp_host = smtp_data.get("smtp_host", "").strip()
        smtp_port = smtp_data.get("smtp_port", "").strip()
        smtp_user = smtp_data.get("smtp_user", "").strip()
        smtp_password = smtp_data.get("smtp_password", "").strip()
        smtp_from_email = smtp_data.get("smtp_from_email", "").strip()
        smtp_from_name = smtp_data.get("smtp_from_name", "").strip()
        smtp_use_tls = smtp_data.get("smtp_use_tls", True)
        

        if smtp_host and not smtp_host:
            raise HTTPException(
                status_code=400,
                detail="SMTP host cannot be empty"
            )
        
        if smtp_port:
            try:
                port_num = int(smtp_port)
                if port_num < 1 or port_num > 65535:
                    raise HTTPException(
                        status_code=400,
                        detail="SMTP port must be between 1 and 65535"
                    )
            except ValueError:
                raise HTTPException(
                    status_code=400,
                    detail="SMTP port must be a valid number"
                )
        
        if smtp_from_email:

            if "@" not in smtp_from_email or "." not in smtp_from_email.split("@")[1]:
                raise HTTPException(
                    status_code=400,
                    detail="Invalid email address format for 'From Email'"
                )
        
        settings_changed = []
        old_values = {}
        
        # Get old values before updating
        smtp_keys = ['smtp_host', 'smtp_port', 'smtp_user', 'smtp_password', 'smtp_from_email', 'smtp_from_name', 'smtp_use_tls']
        for key in smtp_keys:
            old_setting = db.query(SystemSettings).filter(SystemSettings.key == key).first()
            old_values[key] = old_setting.value if old_setting else None

        def update_setting(key: str, value: str, description: str):
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == key
            ).first()
            
            if setting:
                setting.value = value
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key=key,
                    value=value,
                    description=description,
                    updated_by_id=current_user.id
                )
                db.add(setting)
            
            if key not in settings_changed:
                settings_changed.append(key)
        

        if smtp_host:
            update_setting(
                "smtp_host",
                smtp_host,
                "SMTP server hostname (e.g., smtp.gmail.com)"
            )
        
        if smtp_port:
            update_setting(
                "smtp_port",
                smtp_port,
                "SMTP server port (e.g., 587 for STARTTLS, 465 for SSL)"
            )
        
        if smtp_user:
            update_setting(
                "smtp_user",
                smtp_user,
                "SMTP authentication username/email"
            )
        
        if smtp_password:
            update_setting(
                "smtp_password",
                smtp_password,
                "SMTP authentication password (stored securely)"
            )
        
        if smtp_from_email:
            update_setting(
                "smtp_from_email",
                smtp_from_email,
                "Default 'From' email address for outgoing emails"
            )
        
        if smtp_from_name:
            update_setting(
                "smtp_from_name",
                smtp_from_name,
                "Default 'From' name for outgoing emails"
            )
        

        if smtp_use_tls is not None:
            update_setting(
                "smtp_use_tls",
                "true" if smtp_use_tls else "false",
                "Use TLS/SSL for SMTP connection (true for port 465, false for port 587 with STARTTLS)"
            )
        
        db.commit()
        
        # SECURITY: Log SMTP configuration change for audit trail
        if settings_changed:
            try:
                def mask_password(password_value: str) -> str:
                    if not password_value or len(password_value) < 4:
                        return None
                    return "*" * (len(password_value) - 4) + password_value[-4:]
                
                masked_old = {k: (mask_password(v) if 'password' in k.lower() else v) if v else None 
                             for k, v in old_values.items() if k in settings_changed}
                masked_new = {k: (mask_password(v) if 'password' in k.lower() else v) if v else None 
                             for k, v in {
                    'smtp_host': smtp_host if smtp_host else None,
                    'smtp_port': smtp_port if smtp_port else None,
                    'smtp_user': smtp_user if smtp_user else None,
                    'smtp_password': smtp_password if smtp_password else None,
                    'smtp_from_email': smtp_from_email if smtp_from_email else None,
                    'smtp_from_name': smtp_from_name if smtp_from_name else None,
                    'smtp_use_tls': 'true' if smtp_use_tls else 'false' if smtp_use_tls is not None else None
                }.items() if k in settings_changed}
                
                await audit_service.log_action(
                    db=db,
                    action='smtp_config_changed',
                    resource_type='system_settings',
                    user_id=current_user.id,
                    resource_id=None,
                    ip_address=client_ip,
                    user_agent=user_agent,
                    request_id=request_id,
                    details={
                        'settings_changed': settings_changed,
                        'old_values': masked_old,
                        'new_values': masked_new
                    },
                    status='success'
                )
            except Exception as e:
                logger.warning(f'Failed to log SMTP config change audit: {e}')

        def mask_password(password_value: str) -> str:
            if not password_value or len(password_value) < 4:
                return ""
            return "*" * (len(password_value) - 4) + password_value[-4:]
        

        updated_settings = {}
        for key in ["smtp_host", "smtp_port", "smtp_user", "smtp_password", "smtp_from_email", "smtp_from_name", "smtp_use_tls"]:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == key
            ).first()
            if setting:
                updated_settings[key] = setting.value
        
        result = {
            "smtp_host": updated_settings.get("smtp_host", ""),
            "smtp_port": updated_settings.get("smtp_port", ""),
            "smtp_user": updated_settings.get("smtp_user", ""),
            "smtp_password": smtp_password if smtp_password else "",
            "smtp_password_masked": mask_password(updated_settings.get("smtp_password", "")),
            "smtp_from_email": updated_settings.get("smtp_from_email", ""),
            "smtp_from_name": updated_settings.get("smtp_from_name", ""),
            "smtp_use_tls": updated_settings.get("smtp_use_tls", "true").lower() == "true",
            "has_host": bool(updated_settings.get("smtp_host")),
            "has_user": bool(updated_settings.get("smtp_user")),
            "has_password": bool(updated_settings.get("smtp_password")),
        }
        

        password_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "smtp_password"
        ).first()
        if password_setting:
            result["updated_at"] = password_setting.updated_at.isoformat() if password_setting.updated_at else None
            result["updated_by"] = password_setting.updated_by.full_name if password_setting.updated_by else None
        
        return {
            "status": "success",
            "message": "SMTP settings updated successfully",
            "data": result
        }
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))

class TestEmailRequest(BaseModel):
    email: EmailStr

@router.post("/smtp/test")
async def test_smtp_email(
    request: TestEmailRequest,
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    try:
        test_email = str(request.email)
        # Sanitize admin name to prevent XSS/email injection
        from html import escape
        admin_name_raw = current_user.full_name or current_user.email or "Admin"
        admin_name = escape(str(admin_name_raw))  # HTML escape to prevent XSS
        timestamp_str = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
        

        test_html = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>SMTP Test Email</title>
        </head>
        <body style="margin: 0; padding: 0; font-family: Arial, sans-serif; background-color: #f3f4f6;">
            <table role="presentation" style="width: 100%; border-collapse: collapse;">
                <tr>
                    <td style="padding: 40px 20px;">
                        <table role="presentation" style="max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 10px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);">
                            <tr>
                                <td style="padding: 40px; text-align: center; background: linear-gradient(135deg, #1a1a1a 0%, #0f0f0f 100%); border-radius: 10px 10px 0 0;">
                                    <h1 style="color: #d4af37; margin: 0; font-size: 28px;">SMTP Configuration Test</h1>
                                </td>
                            </tr>
                            <tr>
                                <td style="padding: 40px;">
                                    <h2 style="color: #1a1a1a; font-size: 24px; margin-bottom: 20px;">✅ Success!</h2>
                                    <p style="font-size: 16px; color: #374151; line-height: 1.6; margin-bottom: 20px;">
                                        Hello {admin_name},
                                    </p>
                                    <p style="font-size: 16px; color: #374151; line-height: 1.6; margin-bottom: 20px;">
                                        This is a test email to verify that your SMTP configuration is working correctly.
                                    </p>
                                    <div style="background: #d1fae5; border-left: 4px solid #10b981; padding: 15px; margin: 20px 0; border-radius: 4px;">
                                        <p style="margin: 0; color: #065f46; font-size: 14px;">
                                            <strong>Test Details:</strong><br>
                                            Sent by: {admin_name}<br>
                                            Timestamp: {timestamp_str}<br>
                                            Status: SMTP Configuration Active
                                        </p>
                                    </div>
                                    <p style="font-size: 16px; color: #374151; line-height: 1.6; margin-top: 30px;">
                                        If you received this email, your SMTP settings are configured correctly and emails will be sent successfully.
                                    </p>
                                </td>
                            </tr>
                            <tr>
                                <td style="padding: 40px; background-color: #f9fafb; border-radius: 0 0 10px 10px; text-align: center;">
                                    <p style="color: #6b7280; font-size: 12px; margin: 0;">Hotel Booking System - SMTP Test</p>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </body>
        </html>
        """
        

        test_text = f"""
SMTP Configuration Test

Hello {admin_name},

This is a test email to verify that your SMTP configuration is working correctly.

Test Details:
- Sent by: {admin_name}
- Timestamp: {timestamp_str}
- Status: SMTP Configuration Active

If you received this email, your SMTP settings are configured correctly and emails will be sent successfully.

---
Hotel Booking System - SMTP Test
        """.strip()
        

        await send_email(
            to=test_email,
            subject="SMTP Test Email - Hotel Booking System",
            html=test_html,
            text=test_text
        )
        
        sent_at = datetime.utcnow()
        
        return {
            "status": "success",
            "message": f"Test email sent successfully to {test_email}",
            "data": {
                "recipient": test_email,
                "sent_at": sent_at.isoformat()
            }
        }
    except HTTPException:

        raise
    except Exception as e:
        error_msg = str(e)
        logger.error(f"Error sending test email: {type(e).__name__}: {error_msg}", exc_info=True)
        

        if "SMTP mailer not configured" in error_msg:
            raise HTTPException(
                status_code=400,
                detail="SMTP settings are not fully configured. Please configure SMTP Host, Username, and Password in the Email Server settings."
            )
        elif "authentication failed" in error_msg.lower() or "invalid credentials" in error_msg.lower():
            raise HTTPException(
                status_code=400,
                detail="SMTP authentication failed. Please check your SMTP username and password."
            )
        elif "connection" in error_msg.lower() or "timeout" in error_msg.lower():
            raise HTTPException(
                status_code=400,
                detail=f"Cannot connect to SMTP server. Please check your SMTP host and port settings. Error: {error_msg}"
            )
        else:
            raise HTTPException(
                status_code=500,
                detail=f"Failed to send test email: {error_msg}"
            )

class UpdateCompanySettingsRequest(BaseModel):
    company_name: Optional[str] = None
    company_tagline: Optional[str] = None
    company_phone: Optional[str] = None
    company_email: Optional[str] = None
    company_address: Optional[str] = None
    tax_rate: Optional[float] = None
    chat_working_hours_start: Optional[int] = None
    chat_working_hours_end: Optional[int] = None
    bank_name: Optional[str] = None
    bank_account_number: Optional[str] = None
    bank_account_holder: Optional[str] = None
    bank_code: Optional[str] = None

@router.get("/company")
async def get_company_settings(
    db: Session = Depends(get_db)
):
    try:
        setting_keys = [
            "company_name",
            "company_tagline",
            "company_logo_url",
            "company_favicon_url",
            "company_phone",
            "company_email",
            "company_address",
            "tax_rate",
            "chat_working_hours_start",
            "chat_working_hours_end",
            "bank_name",
            "bank_account_number",
            "bank_account_holder",
            "bank_code",
        ]
        
        settings_dict = {}
        for key in setting_keys:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == key
            ).first()
            if setting:
                settings_dict[key] = setting.value
            else:
                settings_dict[key] = None
        

        logo_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "company_logo_url"
        ).first()
        
        updated_at = None
        updated_by = None
        if logo_setting:
            updated_at = logo_setting.updated_at.isoformat() if logo_setting.updated_at else None
            updated_by = logo_setting.updated_by.full_name if logo_setting.updated_by else None
        
        return {
            "status": "success",
            "data": {
                "company_name": settings_dict.get("company_name", ""),
                "company_tagline": settings_dict.get("company_tagline", ""),
                "company_logo_url": settings_dict.get("company_logo_url", ""),
                "company_favicon_url": settings_dict.get("company_favicon_url", ""),
                "company_phone": settings_dict.get("company_phone", ""),
                "company_email": settings_dict.get("company_email", ""),
                "company_address": settings_dict.get("company_address", ""),
                "tax_rate": float(settings_dict.get("tax_rate", 0)) if settings_dict.get("tax_rate") else 0.0,
                "chat_working_hours_start": int(settings_dict.get("chat_working_hours_start", 9)) if settings_dict.get("chat_working_hours_start") else 9,
                "chat_working_hours_end": int(settings_dict.get("chat_working_hours_end", 17)) if settings_dict.get("chat_working_hours_end") else 17,
                "bank_name": settings_dict.get("bank_name", ""),
                "bank_account_number": settings_dict.get("bank_account_number", ""),
                "bank_account_holder": settings_dict.get("bank_account_holder", ""),
                "bank_code": settings_dict.get("bank_code", ""),
                "updated_at": updated_at,
                "updated_by": updated_by,
            }
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.put("/company")
async def update_company_settings(
    request_data: UpdateCompanySettingsRequest,
    request: Request,
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    
    try:
        db_settings = {}
        old_values = {}  # Track old values for financial audit
        
        # Get old values for financial-relevant settings before updating
        if request_data.tax_rate is not None:
            old_tax_setting = db.query(SystemSettings).filter(
                SystemSettings.key == "tax_rate"
            ).first()
            old_values["tax_rate"] = old_tax_setting.value if old_tax_setting else None
        
        if request_data.company_name is not None:
            db_settings["company_name"] = request_data.company_name
        if request_data.company_tagline is not None:
            db_settings["company_tagline"] = request_data.company_tagline
        if request_data.company_phone is not None:
            db_settings["company_phone"] = request_data.company_phone
        if request_data.company_email is not None:
            db_settings["company_email"] = request_data.company_email
        if request_data.company_address is not None:
            db_settings["company_address"] = request_data.company_address
        if request_data.tax_rate is not None:
            db_settings["tax_rate"] = str(request_data.tax_rate)
        if request_data.chat_working_hours_start is not None:
            db_settings["chat_working_hours_start"] = str(request_data.chat_working_hours_start)
        if request_data.chat_working_hours_end is not None:
            db_settings["chat_working_hours_end"] = str(request_data.chat_working_hours_end)
        if request_data.bank_name is not None:
            db_settings["bank_name"] = request_data.bank_name
        if request_data.bank_account_number is not None:
            db_settings["bank_account_number"] = request_data.bank_account_number
        if request_data.bank_account_holder is not None:
            db_settings["bank_account_holder"] = request_data.bank_account_holder
        if request_data.bank_code is not None:
            db_settings["bank_code"] = request_data.bank_code
        
        for key, value in db_settings.items():

            setting = db.query(SystemSettings).filter(
                SystemSettings.key == key
            ).first()
            
            if setting:

                setting.value = value if value else None
                setting.updated_at = datetime.utcnow()
                setting.updated_by_id = current_user.id
            else:

                setting = SystemSettings(
                    key=key,
                    value=value if value else None,
                    updated_by_id=current_user.id
                )
                db.add(setting)
        
        db.commit()
        
        # Log financial audit for tax_rate changes (affects all future invoices)
        if request_data.tax_rate is not None:
            try:
                old_tax = float(old_values.get("tax_rate", 0)) if old_values.get("tax_rate") else 0.0
                new_tax = float(request_data.tax_rate)
                financial_audit_service.log_financial_action(
                    db=db,
                    action_type=FinancialActionType.settings_changed,
                    performed_by=current_user.id,
                    action_description=f'Tax rate changed from {old_tax}% to {new_tax}%',
                    metadata={
                        'setting_key': 'tax_rate',
                        'old_value': str(old_tax),
                        'new_value': str(new_tax),
                        'ip_address': client_ip,
                        'user_agent': user_agent,
                        'request_id': request_id
                    },
                    notes=f'Tax rate setting updated by {current_user.email} - affects all future invoices'
                )
            except Exception as e:
                logger.warning(f'Failed to log financial audit for tax rate change: {e}')
        

        updated_settings = {}
        for key in ["company_name", "company_tagline", "company_logo_url", "company_favicon_url", "company_phone", "company_email", "company_address", "tax_rate", "chat_working_hours_start", "chat_working_hours_end", "bank_name", "bank_account_number", "bank_account_holder", "bank_code"]:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == key
            ).first()
            if setting:
                updated_settings[key] = setting.value
            else:
                updated_settings[key] = None
        

        logo_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "company_logo_url"
        ).first()
        if not logo_setting:
            logo_setting = db.query(SystemSettings).filter(
                SystemSettings.key == "company_name"
            ).first()
        
        updated_at = None
        updated_by = None
        if logo_setting:
            updated_at = logo_setting.updated_at.isoformat() if logo_setting.updated_at else None
            updated_by = logo_setting.updated_by.full_name if logo_setting.updated_by else None
        
        return {
            "status": "success",
            "message": "Company settings updated successfully",
            "data": {
                "company_name": updated_settings.get("company_name", ""),
                "company_tagline": updated_settings.get("company_tagline", ""),
                "company_logo_url": updated_settings.get("company_logo_url", ""),
                "company_favicon_url": updated_settings.get("company_favicon_url", ""),
                "company_phone": updated_settings.get("company_phone", ""),
                "company_email": updated_settings.get("company_email", ""),
                "company_address": updated_settings.get("company_address", ""),
                "tax_rate": float(updated_settings.get("tax_rate", 0)) if updated_settings.get("tax_rate") else 0.0,
                "chat_working_hours_start": int(updated_settings.get("chat_working_hours_start", 9)) if updated_settings.get("chat_working_hours_start") else 9,
                "chat_working_hours_end": int(updated_settings.get("chat_working_hours_end", 17)) if updated_settings.get("chat_working_hours_end") else 17,
                "bank_name": updated_settings.get("bank_name", ""),
                "bank_account_number": updated_settings.get("bank_account_number", ""),
                "bank_account_holder": updated_settings.get("bank_account_holder", ""),
                "bank_code": updated_settings.get("bank_code", ""),
                "updated_at": updated_at,
                "updated_by": updated_by,
            }
        }
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/company/logo")
async def upload_company_logo(
    request: Request,
    image: UploadFile = File(...),
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    try:

        # Validate image using comprehensive validation
        from ...shared.config.settings import settings
        from ...shared.utils.file_validation import validate_uploaded_image
        from ...shared.utils.image_optimization import optimize_image_async, ImageType
        
        max_size = 2 * 1024 * 1024  # 2MB for logos
        content = await validate_uploaded_image(image, max_size)
        
        # Optimize image before saving
        optimized_content, optimized_ext = await optimize_image_async(content, ImageType.COMPANY, preserve_original_format=False)

        upload_dir = Path(__file__).parent.parent.parent.parent / "uploads" / "company"
        upload_dir.mkdir(parents=True, exist_ok=True)
        

        old_logo_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "company_logo_url"
        ).first()
        
        if old_logo_setting and old_logo_setting.value:
            old_logo_path = Path(__file__).parent.parent.parent.parent / old_logo_setting.value.lstrip('/')
            if old_logo_path.exists() and old_logo_path.is_file():
                try:
                    old_logo_path.unlink()
                except Exception as e:
                    logger.warning(f"Could not delete old logo: {e}")
        

        # Use optimized extension, default to webp or png
        ext = optimized_ext or '.webp'
        filename = f"logo{ext}"
        file_path = upload_dir / filename
        

        async with aiofiles.open(file_path, 'wb') as f:
            await f.write(optimized_content)
        

        image_url = f"/uploads/company/{filename}"
        

        logo_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "company_logo_url"
        ).first()
        
        if logo_setting:
            logo_setting.value = image_url
            logo_setting.updated_at = datetime.utcnow()
            logo_setting.updated_by_id = current_user.id
        else:
            logo_setting = SystemSettings(
                key="company_logo_url",
                value=image_url,
                updated_by_id=current_user.id
            )
            db.add(logo_setting)
        
        db.commit()
        

        base_url = get_base_url(request)
        full_url = normalize_image_url(image_url, base_url)
        
        return {
            "success": True,
            "status": "success",
            "message": "Logo uploaded successfully",
            "data": {
                "logo_url": image_url,
                "full_url": full_url
            }
        }
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f"Error uploading logo: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/company/favicon")
async def upload_company_favicon(
    request: Request,
    image: UploadFile = File(...),
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    try:

        # Validate image
        from ...shared.config.settings import settings
        from ...shared.utils.file_validation import validate_uploaded_image
        from ...shared.utils.image_optimization import optimize_image_async, ImageType
        
        max_size = 500 * 1024  # 500KB for favicons
        
        # For favicons, we need to check if it's SVG (text format) or image format
        filename_lower = (image.filename or '').lower()
        is_svg = filename_lower.endswith('.svg')
        
        if is_svg:
            # For SVG, just validate size (can't optimize SVG with PIL)
            content = await image.read()
            if len(content) > max_size:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="Favicon file size must be less than 500KB"
                )
            # Keep SVG as-is
            optimized_content = content
            optimized_ext = '.svg'
        else:
            # For ICO/PNG, validate and optimize
            if not image.content_type:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="File type could not be determined"
                )
            
            allowed_types = ['image/x-icon', 'image/vnd.microsoft.icon', 'image/png', 'image/ico']
            if image.content_type not in allowed_types:
                if not any(filename_lower.endswith(ext) for ext in ['.ico', '.png']):
                    raise HTTPException(
                        status_code=status.HTTP_400_BAD_REQUEST,
                        detail="Favicon must be .ico or .png file"
                    )
            
            content = await validate_uploaded_image(image, max_size)
            
            # Optimize favicon but preserve format (ICO/PNG)
            optimized_content, optimized_ext = await optimize_image_async(
                content, 
                ImageType.COMPANY, 
                preserve_original_format=True  # Keep original format for favicons
            )

        upload_dir = Path(__file__).parent.parent.parent.parent / "uploads" / "company"
        upload_dir.mkdir(parents=True, exist_ok=True)
        

        old_favicon_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "company_favicon_url"
        ).first()
        
        if old_favicon_setting and old_favicon_setting.value:
            old_favicon_path = Path(__file__).parent.parent.parent.parent / old_favicon_setting.value.lstrip('/')
            if old_favicon_path.exists() and old_favicon_path.is_file():
                try:
                    old_favicon_path.unlink()
                except Exception as e:
                    logger.warning(f"Could not delete old favicon: {e}")
        

        # Determine filename based on original or optimized extension
        if is_svg or filename_lower.endswith('.svg'):
            filename = "favicon.svg"
        elif optimized_ext == '.ico' or filename_lower.endswith('.ico'):
            filename = "favicon.ico"
        else:
            filename = "favicon.png"
        
        file_path = upload_dir / filename
        

        async with aiofiles.open(file_path, 'wb') as f:
            await f.write(optimized_content)
        

        image_url = f"/uploads/company/{filename}"
        

        favicon_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "company_favicon_url"
        ).first()
        
        if favicon_setting:
            favicon_setting.value = image_url
            favicon_setting.updated_at = datetime.utcnow()
            favicon_setting.updated_by_id = current_user.id
        else:
            favicon_setting = SystemSettings(
                key="company_favicon_url",
                value=image_url,
                updated_by_id=current_user.id
            )
            db.add(favicon_setting)
        
        db.commit()
        

        base_url = get_base_url(request)
        full_url = normalize_image_url(image_url, base_url)
        
        return {
            "success": True,
            "status": "success",
            "message": "Favicon uploaded successfully",
            "data": {
                "favicon_url": image_url,
                "full_url": full_url
            }
        }
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f"Error uploading favicon: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

class UpdateThemeSettingsRequest(BaseModel):
    theme_primary_color: Optional[str] = None
    theme_primary_light: Optional[str] = None
    theme_primary_dark: Optional[str] = None
    theme_primary_accent: Optional[str] = None
    theme_layout_mode: Optional[str] = None  # 'dark' or 'light'

@router.get("/theme")
async def get_theme_settings(
    db: Session = Depends(get_db)
):
    """Get current theme color settings"""
    try:
        setting_keys = [
            "theme_primary_color",
            "theme_primary_light",
            "theme_primary_dark",
            "theme_primary_accent",
            "theme_layout_mode",
        ]
        
        settings_dict = {}
        for key in setting_keys:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == key
            ).first()
            if setting:
                settings_dict[key] = setting.value
            else:
                settings_dict[key] = None
        
        # Get updated_at and updated_by from any theme setting
        theme_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "theme_primary_color"
        ).first()
        
        updated_at = None
        updated_by = None
        if theme_setting:
            updated_at = theme_setting.updated_at.isoformat() if theme_setting.updated_at else None
            updated_by = theme_setting.updated_by.full_name if theme_setting.updated_by else None
        
        return {
            "status": "success",
            "data": {
                "theme_primary_color": settings_dict.get("theme_primary_color", "#d4af37"),
                "theme_primary_light": settings_dict.get("theme_primary_light", "#f5d76e"),
                "theme_primary_dark": settings_dict.get("theme_primary_dark", "#c9a227"),
                "theme_primary_accent": settings_dict.get("theme_primary_accent", "#e8c547"),
                "theme_layout_mode": settings_dict.get("theme_layout_mode", "dark"),
                "updated_at": updated_at,
                "updated_by": updated_by,
            }
        }
    except Exception as e:
        logger.error(f"Error getting theme settings: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

@router.put("/theme")
async def update_theme_settings(
    request_data: UpdateThemeSettingsRequest,
    request: Request,
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    """Update theme color settings (admin only)"""
    import re
    
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    
    try:
        # Validate hex color format
        hex_color_pattern = re.compile(r'^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$')
        
        db_settings = {}
        
        if request_data.theme_primary_color is not None:
            if not hex_color_pattern.match(request_data.theme_primary_color):
                raise HTTPException(
                    status_code=400,
                    detail="Invalid theme_primary_color format. Must be a valid hex color (e.g., #d4af37)"
                )
            db_settings["theme_primary_color"] = request_data.theme_primary_color
        
        if request_data.theme_primary_light is not None:
            if not hex_color_pattern.match(request_data.theme_primary_light):
                raise HTTPException(
                    status_code=400,
                    detail="Invalid theme_primary_light format. Must be a valid hex color (e.g., #f5d76e)"
                )
            db_settings["theme_primary_light"] = request_data.theme_primary_light
        
        if request_data.theme_primary_dark is not None:
            if not hex_color_pattern.match(request_data.theme_primary_dark):
                raise HTTPException(
                    status_code=400,
                    detail="Invalid theme_primary_dark format. Must be a valid hex color (e.g., #c9a227)"
                )
            db_settings["theme_primary_dark"] = request_data.theme_primary_dark
        
        if request_data.theme_primary_accent is not None:
            if not hex_color_pattern.match(request_data.theme_primary_accent):
                raise HTTPException(
                    status_code=400,
                    detail="Invalid theme_primary_accent format. Must be a valid hex color (e.g., #e8c547)"
                )
            db_settings["theme_primary_accent"] = request_data.theme_primary_accent
        
        if request_data.theme_layout_mode is not None:
            if request_data.theme_layout_mode not in ["dark", "light"]:
                raise HTTPException(
                    status_code=400,
                    detail="Invalid theme_layout_mode. Must be 'dark' or 'light'"
                )
            db_settings["theme_layout_mode"] = request_data.theme_layout_mode
        
        # Update or create settings
        for key, value in db_settings.items():
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == key
            ).first()
            
            if setting:
                setting.value = value
                setting.updated_at = datetime.utcnow()
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key=key,
                    value=value,
                    updated_by_id=current_user.id
                )
                db.add(setting)
        
        db.commit()
        
        # Get updated settings
        updated_settings = {}
        for key in ["theme_primary_color", "theme_primary_light", "theme_primary_dark", "theme_primary_accent", "theme_layout_mode"]:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == key
            ).first()
            if setting:
                updated_settings[key] = setting.value
            else:
                # Return defaults if not set
                defaults = {
                    "theme_primary_color": "#d4af37",
                    "theme_primary_light": "#f5d76e",
                    "theme_primary_dark": "#c9a227",
                    "theme_primary_accent": "#e8c547",
                    "theme_layout_mode": "dark",
                }
                updated_settings[key] = defaults.get(key)
        
        theme_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "theme_primary_color"
        ).first()
        
        updated_at = None
        updated_by = None
        if theme_setting:
            updated_at = theme_setting.updated_at.isoformat() if theme_setting.updated_at else None
            updated_by = theme_setting.updated_by.full_name if theme_setting.updated_by else None
        
        return {
            "status": "success",
            "message": "Theme settings updated successfully",
            "data": {
                "theme_primary_color": updated_settings.get("theme_primary_color", "#d4af37"),
                "theme_primary_light": updated_settings.get("theme_primary_light", "#f5d76e"),
                "theme_primary_dark": updated_settings.get("theme_primary_dark", "#c9a227"),
                "theme_primary_accent": updated_settings.get("theme_primary_accent", "#e8c547"),
                "theme_layout_mode": updated_settings.get("theme_layout_mode", "dark"),
                "updated_at": updated_at,
                "updated_by": updated_by,
            }
        }
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f"Error updating theme settings: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/recaptcha")
async def get_recaptcha_settings(
    db: Session = Depends(get_db)
):
    try:
        site_key_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "recaptcha_site_key"
        ).first()
        
        enabled_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "recaptcha_enabled"
        ).first()
        
        result = {
            "recaptcha_site_key": "",
            "recaptcha_enabled": False,
        }
        
        if site_key_setting:
            result["recaptcha_site_key"] = site_key_setting.value or ""
        
        if enabled_setting:
            result["recaptcha_enabled"] = enabled_setting.value.lower() == "true" if enabled_setting.value else False
        
        return {
            "status": "success",
            "data": result
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/recaptcha/admin")
async def get_recaptcha_settings_admin(
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    try:
        site_key_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "recaptcha_site_key"
        ).first()
        
        secret_key_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "recaptcha_secret_key"
        ).first()
        
        enabled_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "recaptcha_enabled"
        ).first()
        

        def mask_key(key_value: str) -> str:
            if not key_value or len(key_value) < 4:
                return ""
            return "*" * (len(key_value) - 4) + key_value[-4:]
        
        result = {
            "recaptcha_site_key": "",
            "recaptcha_secret_key": "",
            "recaptcha_secret_key_masked": "",
            "recaptcha_enabled": False,
            "has_site_key": False,
            "has_secret_key": False,
        }
        
        if site_key_setting:
            result["recaptcha_site_key"] = site_key_setting.value or ""
            result["has_site_key"] = bool(site_key_setting.value)
            result["updated_at"] = site_key_setting.updated_at.isoformat() if site_key_setting.updated_at else None
            result["updated_by"] = site_key_setting.updated_by.full_name if site_key_setting.updated_by else None
        
        if secret_key_setting:
            result["recaptcha_secret_key"] = secret_key_setting.value or ""
            result["recaptcha_secret_key_masked"] = mask_key(secret_key_setting.value or "")
            result["has_secret_key"] = bool(secret_key_setting.value)
        
        if enabled_setting:
            result["recaptcha_enabled"] = enabled_setting.value.lower() == "true" if enabled_setting.value else False
        
        return {
            "status": "success",
            "data": result
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.put("/recaptcha")
async def update_recaptcha_settings(
    recaptcha_data: dict,
    current_user: User = Depends(authorize_roles("admin")),
    db: Session = Depends(get_db)
):
    try:
        site_key = recaptcha_data.get("recaptcha_site_key", "").strip()
        secret_key = recaptcha_data.get("recaptcha_secret_key", "").strip()
        enabled = recaptcha_data.get("recaptcha_enabled", False)
        

        if site_key:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "recaptcha_site_key"
            ).first()
            
            if setting:
                setting.value = site_key
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="recaptcha_site_key",
                    value=site_key,
                    description="Google reCAPTCHA site key for frontend",
                    updated_by_id=current_user.id
                )
                db.add(setting)
        

        if secret_key:
            setting = db.query(SystemSettings).filter(
                SystemSettings.key == "recaptcha_secret_key"
            ).first()
            
            if setting:
                setting.value = secret_key
                setting.updated_by_id = current_user.id
            else:
                setting = SystemSettings(
                    key="recaptcha_secret_key",
                    value=secret_key,
                    description="Google reCAPTCHA secret key for backend verification",
                    updated_by_id=current_user.id
                )
                db.add(setting)
        

        setting = db.query(SystemSettings).filter(
            SystemSettings.key == "recaptcha_enabled"
        ).first()
        
        if setting:
            setting.value = str(enabled).lower()
            setting.updated_by_id = current_user.id
        else:
            setting = SystemSettings(
                key="recaptcha_enabled",
                value=str(enabled).lower(),
                description="Enable or disable reCAPTCHA verification",
                updated_by_id=current_user.id
            )
            db.add(setting)
        
        db.commit()
        

        def mask_key(key_value: str) -> str:
            if not key_value or len(key_value) < 4:
                return ""
            return "*" * (len(key_value) - 4) + key_value[-4:]
        
        return {
            "status": "success",
            "message": "reCAPTCHA settings updated successfully",
            "data": {
                "recaptcha_site_key": site_key if site_key else "",
                "recaptcha_secret_key": secret_key if secret_key else "",
                "recaptcha_secret_key_masked": mask_key(secret_key) if secret_key else "",
                "recaptcha_enabled": enabled,
                "has_site_key": bool(site_key),
                "has_secret_key": bool(secret_key),
            }
        }
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/recaptcha/verify")
async def verify_recaptcha(
    verification_data: dict,
    db: Session = Depends(get_db)
):
    try:
        token = verification_data.get("token", "").strip()
        
        if not token:
            raise HTTPException(
                status_code=400,
                detail="reCAPTCHA token is required"
            )
        

        enabled_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "recaptcha_enabled"
        ).first()
        
        secret_key_setting = db.query(SystemSettings).filter(
            SystemSettings.key == "recaptcha_secret_key"
        ).first()
        

        is_enabled = False
        if enabled_setting:
            is_enabled = enabled_setting.value.lower() == "true" if enabled_setting.value else False
        
        if not is_enabled:

            return {
                "status": "success",
                "data": {
                    "verified": True,
                    "message": "reCAPTCHA is disabled"
                }
            }
        
        if not secret_key_setting or not secret_key_setting.value:
            raise HTTPException(
                status_code=500,
                detail="reCAPTCHA secret key is not configured"
            )
        

        import httpx
        
        async with httpx.AsyncClient() as client:
            response = await client.post(
                "https://www.google.com/recaptcha/api/siteverify",
                data={
                    "secret": secret_key_setting.value,
                    "response": token
                },
                timeout=10.0
            )
            
            result = response.json()
            
            if result.get("success"):
                return {
                    "status": "success",
                    "data": {
                        "verified": True,
                        "score": result.get("score"),
                        "action": result.get("action")
                    }
                }
            else:
                error_codes = result.get("error-codes", [])
                return {
                    "status": "error",
                    "data": {
                        "verified": False,
                        "error_codes": error_codes
                    }
                }
    except httpx.TimeoutException:
        raise HTTPException(
            status_code=408,
            detail="reCAPTCHA verification timeout"
        )
    except Exception as e:
        logger.error(f"Error verifying reCAPTCHA: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

