from fastapi import APIRouter, Depends, HTTPException, Query, Body
from sqlalchemy.orm import Session
from typing import Optional, List, Dict, Any
from ..config.database import get_db
from ..middleware.auth import authorize_roles, get_current_user
from ..models.user import User
from ..models.notification import NotificationChannel, NotificationStatus, NotificationType
from ..services.notification_service import NotificationService
from pydantic import BaseModel
from datetime import datetime

router = APIRouter(prefix='/notifications', tags=['notifications'])

# Request/Response Models
class NotificationSendRequest(BaseModel):
    user_id: Optional[int] = None
    notification_type: str
    channel: str
    content: str
    subject: Optional[str] = None
    template_id: Optional[int] = None
    priority: Optional[str] = 'normal'
    scheduled_at: Optional[str] = None
    booking_id: Optional[int] = None
    payment_id: Optional[int] = None
    meta_data: Optional[Dict[str, Any]] = None

class TemplateCreateRequest(BaseModel):
    name: str
    notification_type: str
    channel: str
    content: str
    subject: Optional[str] = None
    variables: Optional[List[str]] = None

class PreferencesUpdateRequest(BaseModel):
    email_enabled: Optional[bool] = None
    sms_enabled: Optional[bool] = None
    push_enabled: Optional[bool] = None
    whatsapp_enabled: Optional[bool] = None
    in_app_enabled: Optional[bool] = None
    booking_confirmation_email: Optional[bool] = None
    booking_confirmation_sms: Optional[bool] = None
    payment_receipt_email: Optional[bool] = None
    payment_receipt_sms: Optional[bool] = None
    pre_arrival_reminder_email: Optional[bool] = None
    pre_arrival_reminder_sms: Optional[bool] = None
    check_in_reminder_email: Optional[bool] = None
    check_in_reminder_sms: Optional[bool] = None
    check_out_reminder_email: Optional[bool] = None
    check_out_reminder_sms: Optional[bool] = None
    marketing_campaign_email: Optional[bool] = None
    marketing_campaign_sms: Optional[bool] = None
    loyalty_update_email: Optional[bool] = None
    loyalty_update_sms: Optional[bool] = None
    system_alert_email: Optional[bool] = None
    system_alert_push: Optional[bool] = None

# Notifications
@router.get('/')
async def get_notifications(
    user_id: Optional[int] = Query(None),
    notification_type: Optional[str] = Query(None),
    channel: Optional[str] = Query(None),
    status: Optional[str] = Query(None),
    skip: int = Query(0, ge=0),
    limit: int = Query(100, ge=1, le=1000),
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Get notifications"""
    try:
        notifications = NotificationService.get_notifications(
            db=db,
            user_id=user_id,
            notification_type=NotificationType(notification_type) if notification_type else None,
            channel=NotificationChannel(channel) if channel else None,
            status=NotificationStatus(status) if status else None,
            skip=skip,
            limit=limit
        )
        return {'status': 'success', 'data': [{
            'id': n.id,
            'user_id': n.user_id,
            'notification_type': n.notification_type.value,
            'channel': n.channel.value,
            'subject': n.subject,
            'content': n.content,
            'status': n.status.value,
            'priority': n.priority,
            'sent_at': n.sent_at.isoformat() if n.sent_at else None,
            'delivered_at': n.delivered_at.isoformat() if n.delivered_at else None,
            'read_at': n.read_at.isoformat() if n.read_at else None,
            'created_at': n.created_at.isoformat(),
        } for n in notifications]}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get('/my-notifications')
async def get_my_notifications(
    status: Optional[str] = Query(None),
    skip: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=100),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Get current user's notifications"""
    try:
        notifications = NotificationService.get_notifications(
            db=db,
            user_id=current_user.id,
            status=NotificationStatus(status) if status else None,
            skip=skip,
            limit=limit
        )
        return {'status': 'success', 'data': [{
            'id': n.id,
            'notification_type': n.notification_type.value,
            'channel': n.channel.value,
            'subject': n.subject,
            'content': n.content,
            'status': n.status.value,
            'read_at': n.read_at.isoformat() if n.read_at else None,
            'created_at': n.created_at.isoformat(),
        } for n in notifications]}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post('/send')
async def send_notification(
    notification_data: NotificationSendRequest,
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Send notification"""
    try:
        scheduled_at = None
        if notification_data.scheduled_at:
            scheduled_at = datetime.fromisoformat(notification_data.scheduled_at.replace('Z', '+00:00'))
        
        notification = NotificationService.send_notification(
            db=db,
            user_id=notification_data.user_id,
            notification_type=NotificationType(notification_data.notification_type),
            channel=NotificationChannel(notification_data.channel),
            content=notification_data.content,
            subject=notification_data.subject,
            template_id=notification_data.template_id,
            priority=notification_data.priority or 'normal',
            scheduled_at=scheduled_at,
            booking_id=notification_data.booking_id,
            payment_id=notification_data.payment_id,
            meta_data=notification_data.meta_data
        )
        return {'status': 'success', 'data': {
            'id': notification.id,
            'status': notification.status.value,
            'created_at': notification.created_at.isoformat()
        }}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post('/{notification_id}/read')
async def mark_notification_read(
    notification_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Mark notification as read"""
    try:
        notification = NotificationService.mark_as_read(db, notification_id, current_user.id)
        if not notification:
            raise HTTPException(status_code=404, detail='Notification not found')
        
        return {'status': 'success', 'data': {
            'id': notification.id,
            'status': notification.status.value,
            'read_at': notification.read_at.isoformat() if notification.read_at else None
        }}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# Templates
@router.post('/templates')
async def create_template(
    template_data: TemplateCreateRequest,
    current_user: User = Depends(authorize_roles('admin')),
    db: Session = Depends(get_db)
):
    """Create notification template"""
    try:
        template = NotificationService.create_template(
            db=db,
            name=template_data.name,
            notification_type=NotificationType(template_data.notification_type),
            channel=NotificationChannel(template_data.channel),
            content=template_data.content,
            created_by=current_user.id,
            subject=template_data.subject,
            variables=template_data.variables
        )
        return {'status': 'success', 'data': {
            'id': template.id,
            'name': template.name,
            'created_at': template.created_at.isoformat()
        }}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get('/templates')
async def get_templates(
    notification_type: Optional[str] = Query(None),
    channel: Optional[str] = Query(None),
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Get notification templates"""
    try:
        from ..models.notification import NotificationTemplate
        query = db.query(NotificationTemplate)
        
        if notification_type:
            query = query.filter(NotificationTemplate.notification_type == NotificationType(notification_type))
        if channel:
            query = query.filter(NotificationTemplate.channel == NotificationChannel(channel))
        
        templates = query.filter(NotificationTemplate.is_active == True).all()
        return {'status': 'success', 'data': [{
            'id': t.id,
            'name': t.name,
            'notification_type': t.notification_type.value,
            'channel': t.channel.value,
            'subject': t.subject,
            'content': t.content,
            'variables': t.variables,
        } for t in templates]}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# Preferences
@router.get('/preferences')
async def get_preferences(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Get user notification preferences"""
    try:
        preferences = NotificationService.get_user_preferences(db, current_user.id)
        return {'status': 'success', 'data': {
            'email_enabled': preferences.email_enabled,
            'sms_enabled': preferences.sms_enabled,
            'push_enabled': preferences.push_enabled,
            'whatsapp_enabled': preferences.whatsapp_enabled,
            'in_app_enabled': preferences.in_app_enabled,
            'booking_confirmation_email': preferences.booking_confirmation_email,
            'booking_confirmation_sms': preferences.booking_confirmation_sms,
            'payment_receipt_email': preferences.payment_receipt_email,
            'payment_receipt_sms': preferences.payment_receipt_sms,
            'pre_arrival_reminder_email': preferences.pre_arrival_reminder_email,
            'pre_arrival_reminder_sms': preferences.pre_arrival_reminder_sms,
            'check_in_reminder_email': preferences.check_in_reminder_email,
            'check_in_reminder_sms': preferences.check_in_reminder_sms,
            'check_out_reminder_email': preferences.check_out_reminder_email,
            'check_out_reminder_sms': preferences.check_out_reminder_sms,
            'marketing_campaign_email': preferences.marketing_campaign_email,
            'marketing_campaign_sms': preferences.marketing_campaign_sms,
            'loyalty_update_email': preferences.loyalty_update_email,
            'loyalty_update_sms': preferences.loyalty_update_sms,
            'system_alert_email': preferences.system_alert_email,
            'system_alert_push': preferences.system_alert_push,
        }}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.put('/preferences')
async def update_preferences(
    preferences_data: PreferencesUpdateRequest,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Update user notification preferences"""
    try:
        prefs_dict = preferences_data.dict(exclude_unset=True)
        preferences = NotificationService.update_user_preferences(db, current_user.id, prefs_dict)
        return {'status': 'success', 'data': {
            'email_enabled': preferences.email_enabled,
            'sms_enabled': preferences.sms_enabled,
            'push_enabled': preferences.push_enabled,
            'whatsapp_enabled': preferences.whatsapp_enabled,
            'in_app_enabled': preferences.in_app_enabled,
        }}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

