from celery import shared_task
from sqlalchemy.orm import Session
from datetime import datetime, timedelta
from app.db.session import SessionLocal
from app.db.models import Notification, Customer, Delivery, Segment
from app.workers.deliveries import deliver_message
from app.core.config import get_settings


@shared_task(bind=True, name="app.workers.notifications.enqueue_notification")
def enqueue_notification(self, notification_id: int) -> str:
    """
    Expand notification to individual deliveries per customer and channel
    
    Args:
        notification_id: Notification record ID
    
    Flow:
    1. Resolve segment or single customer
    2. For each customer, create Delivery records per channel (based on template.channel_strategy)
    3. Enqueue deliver_message tasks
    """
    db: Session = SessionLocal()
    
    try:
        notification = db.query(Notification).filter(Notification.id == notification_id).first()
        if not notification:
            return f"notification:{notification_id}:not_found"
        
        # Resolve recipients
        customers = []
        if notification.customer_id:
            customer = db.query(Customer).filter(Customer.id == notification.customer_id).first()
            if customer:
                customers = [customer]
        elif notification.segment_id:
            segment = db.query(Segment).filter(Segment.id == notification.segment_id).first()
            if segment:
                # Simple segment filter (tags IN)
                filter_config = segment.filter or {}
                query = db.query(Customer).filter(Customer.tenant_id == notification.tenant_id)
                
                if "tags" in filter_config:
                    query = query.filter(Customer.tags.overlap(filter_config["tags"]))
                
                customers = query.all()
        
        if not customers:
            notification.status = "failed"
            db.commit()
            return f"notification:{notification_id}:no_recipients"
        
        # Create deliveries based on channel strategy
        channel_strategy = notification.template.channel_strategy or {"primary": ["email"]}
        channels = channel_strategy.get("primary", ["email"])
        
        delivery_count = 0
        for customer in customers:
            for channel in channels:
                # Map channel to customer contact
                target = None
                if channel == "telegram" and customer.tg_chat_id:
                    target = customer.tg_chat_id
                elif channel == "vk" and customer.vk_user_id:
                    target = customer.vk_user_id
                elif channel == "email" and customer.email:
                    target = customer.email
                # elif channel == "whatsapp" and customer.phone:
                #     target = customer.phone
                
                if target:
                    delivery = Delivery(
                        notification_id=notification.id,
                        channel=channel,
                        target=target,
                        status="pending",
                        attempts=0
                    )
                    db.add(delivery)
                    db.flush()
                    
                    # Enqueue delivery task
                    deliver_message.delay(delivery.id)
                    delivery_count += 1
        
        notification.status = "processing"
        db.commit()
        
        return f"notification:{notification_id}:enqueued:{delivery_count}"
    
    finally:
        db.close()


@shared_task(bind=True, name="app.workers.notifications.cleanup_logs")
def cleanup_logs(self) -> str:
    """
    Periodic task to clean up old delivery logs (retention policy)
    
    Удаляет записи доставки старше указанного периода (по умолчанию 90 дней).
    Использует поле sent_at для определения возраста записи.
    Удаляет только записи с установленным sent_at (завершенные доставки).
    Записи без sent_at (pending) не удаляются, так как они могут быть еще в обработке.
    """
    db: Session = SessionLocal()
    
    try:
        settings = get_settings()
        retention_days = settings.DELIVERY_LOG_RETENTION_DAYS
        
        # Вычисляем дату отсечки (все записи старше этой даты будут удалены)
        cutoff_date = datetime.utcnow() - timedelta(days=retention_days)
        
        # Удаляем записи с sent_at старше cutoff_date
        # Это безопасно, так как эти записи уже завершены (отправлены или failed)
        deleted_count = db.query(Delivery).filter(
            Delivery.sent_at.isnot(None),
            Delivery.sent_at < cutoff_date
        ).delete(synchronize_session=False)
        
        db.commit()
        
        return f"ok: deleted {deleted_count} delivery logs older than {retention_days} days (cutoff: {cutoff_date.date()})"
    
    except Exception as e:
        db.rollback()
        # Логируем ошибку, но не падаем - задача будет повторена при следующем запуске
        return f"error: {str(e)}"
    
    finally:
        db.close()
