"""
Notification service for managing and sending notifications.
"""
from datetime import datetime
from typing import Optional
from sqlalchemy.orm import Session

from app.models.notification import (
    Notification,
    NotificationSetting,
    NotificationType,
    NotificationTemplate,
    NotificationStatus
)
from app.models.reservation import Reservation
from app.models.client import Client
from app.models.folio import Folio
from app.models.establishment import Establishment
from app.services.email_service import EmailService
from app.services.notification_templates import EmailTemplates


class NotificationService:
    """Service for creating and sending notifications."""

    @staticmethod
    def send_reservation_confirmation(
        db: Session,
        reservation: Reservation
    ) -> Optional[Notification]:
        """Send reservation confirmation email."""
        if not reservation.client or not reservation.client.email:
            return None

        # Get establishment (through room)
        establishment = reservation.room.establishment if reservation.room else None
        if not establishment:
            return None

        # Get notification settings
        settings = db.query(NotificationSetting).filter(
            NotificationSetting.establishment_id == establishment.id
        ).first()

        if not settings or not settings.auto_send_confirmation:
            return None

        # Generate email content
        subject, html_body = EmailTemplates.reservation_confirmation(
            reservation, reservation.client, establishment
        )

        # Create notification record
        notification = Notification(
            notification_type=NotificationType.EMAIL,
            template=NotificationTemplate.RESERVATION_CONFIRMATION,
            recipient_email=reservation.client.email,
            recipient_name=reservation.client.full_name,
            subject=subject,
            body=html_body,
            client_id=reservation.client_id,
            reservation_id=reservation.id,
            status=NotificationStatus.PENDING
        )
        db.add(notification)
        db.commit()

        # Send email
        success, error = EmailService.send_email(
            settings=settings,
            to_email=reservation.client.email,
            subject=subject,
            html_body=html_body
        )

        # Update notification status
        if success:
            notification.status = NotificationStatus.SENT
            notification.sent_at = datetime.utcnow()
        else:
            notification.status = NotificationStatus.FAILED
            notification.error_message = error
            notification.retry_count += 1

        db.commit()
        return notification

    @staticmethod
    def send_reservation_modification(
        db: Session,
        reservation: Reservation
    ) -> Optional[Notification]:
        """Send reservation modification email."""
        if not reservation.client or not reservation.client.email:
            return None

        establishment = reservation.room.establishment if reservation.room else None
        if not establishment:
            return None

        settings = db.query(NotificationSetting).filter(
            NotificationSetting.establishment_id == establishment.id
        ).first()

        if not settings or not settings.auto_send_modification:
            return None

        subject, html_body = EmailTemplates.reservation_modification(
            reservation, reservation.client, establishment
        )

        notification = Notification(
            notification_type=NotificationType.EMAIL,
            template=NotificationTemplate.RESERVATION_MODIFICATION,
            recipient_email=reservation.client.email,
            recipient_name=reservation.client.full_name,
            subject=subject,
            body=html_body,
            client_id=reservation.client_id,
            reservation_id=reservation.id,
            status=NotificationStatus.PENDING
        )
        db.add(notification)
        db.commit()

        success, error = EmailService.send_email(
            settings=settings,
            to_email=reservation.client.email,
            subject=subject,
            html_body=html_body
        )

        if success:
            notification.status = NotificationStatus.SENT
            notification.sent_at = datetime.utcnow()
        else:
            notification.status = NotificationStatus.FAILED
            notification.error_message = error
            notification.retry_count += 1

        db.commit()
        return notification

    @staticmethod
    def send_reservation_cancellation(
        db: Session,
        reservation: Reservation
    ) -> Optional[Notification]:
        """Send reservation cancellation email."""
        if not reservation.client or not reservation.client.email:
            return None

        establishment = reservation.room.establishment if reservation.room else None
        if not establishment:
            return None

        settings = db.query(NotificationSetting).filter(
            NotificationSetting.establishment_id == establishment.id
        ).first()

        if not settings or not settings.auto_send_cancellation:
            return None

        subject, html_body = EmailTemplates.reservation_cancellation(
            reservation, reservation.client, establishment
        )

        notification = Notification(
            notification_type=NotificationType.EMAIL,
            template=NotificationTemplate.RESERVATION_CANCELLATION,
            recipient_email=reservation.client.email,
            recipient_name=reservation.client.full_name,
            subject=subject,
            body=html_body,
            client_id=reservation.client_id,
            reservation_id=reservation.id,
            status=NotificationStatus.PENDING
        )
        db.add(notification)
        db.commit()

        success, error = EmailService.send_email(
            settings=settings,
            to_email=reservation.client.email,
            subject=subject,
            html_body=html_body
        )

        if success:
            notification.status = NotificationStatus.SENT
            notification.sent_at = datetime.utcnow()
        else:
            notification.status = NotificationStatus.FAILED
            notification.error_message = error
            notification.retry_count += 1

        db.commit()
        return notification

    @staticmethod
    def send_check_in_confirmation(
        db: Session,
        reservation: Reservation
    ) -> Optional[Notification]:
        """Send check-in confirmation email."""
        if not reservation.client or not reservation.client.email:
            return None

        establishment = reservation.room.establishment if reservation.room else None
        if not establishment:
            return None

        settings = db.query(NotificationSetting).filter(
            NotificationSetting.establishment_id == establishment.id
        ).first()

        if not settings or not settings.email_enabled:
            return None

        subject, html_body = EmailTemplates.check_in_confirmation(
            reservation, reservation.client, establishment
        )

        notification = Notification(
            notification_type=NotificationType.EMAIL,
            template=NotificationTemplate.CHECK_IN_CONFIRMATION,
            recipient_email=reservation.client.email,
            recipient_name=reservation.client.full_name,
            subject=subject,
            body=html_body,
            client_id=reservation.client_id,
            reservation_id=reservation.id,
            status=NotificationStatus.PENDING
        )
        db.add(notification)
        db.commit()

        success, error = EmailService.send_email(
            settings=settings,
            to_email=reservation.client.email,
            subject=subject,
            html_body=html_body
        )

        if success:
            notification.status = NotificationStatus.SENT
            notification.sent_at = datetime.utcnow()
        else:
            notification.status = NotificationStatus.FAILED
            notification.error_message = error
            notification.retry_count += 1

        db.commit()
        return notification

    @staticmethod
    def send_invoice_email(
        db: Session,
        folio: Folio
    ) -> Optional[Notification]:
        """Send invoice email."""
        if not folio.reservation or not folio.reservation.client or not folio.reservation.client.email:
            return None

        establishment = folio.reservation.room.establishment if folio.reservation.room else None
        if not establishment:
            return None

        settings = db.query(NotificationSetting).filter(
            NotificationSetting.establishment_id == establishment.id
        ).first()

        if not settings or not settings.email_enabled:
            return None

        subject, html_body = EmailTemplates.invoice_email(
            folio, folio.reservation.client, establishment
        )

        notification = Notification(
            notification_type=NotificationType.EMAIL,
            template=NotificationTemplate.INVOICE,
            recipient_email=folio.reservation.client.email,
            recipient_name=folio.reservation.client.full_name,
            subject=subject,
            body=html_body,
            client_id=folio.reservation.client_id,
            folio_id=folio.id,
            status=NotificationStatus.PENDING
        )
        db.add(notification)
        db.commit()

        success, error = EmailService.send_email(
            settings=settings,
            to_email=folio.reservation.client.email,
            subject=subject,
            html_body=html_body
        )

        if success:
            notification.status = NotificationStatus.SENT
            notification.sent_at = datetime.utcnow()
        else:
            notification.status = NotificationStatus.FAILED
            notification.error_message = error
            notification.retry_count += 1

        db.commit()
        return notification
