from datetime import datetime, timezone, timedelta
from decimal import Decimal
from croniter import croniter
from sqlalchemy import select
from app.core.database import SessionLocal
from app.models.entities import AlertRule, AlertEvent, Notification, User, Message
from app.services.analytics import execute_definition

def compare(value,op,threshold):
    a,b=Decimal(str(value)),Decimal(str(threshold)); return {'lt':a<b,'lte':a<=b,'gt':a>b,'gte':a>=b,'eq':a==b,'ne':a!=b}.get(op,False)

def evaluate_alerts():
    db=SessionLocal(); now=datetime.now(timezone.utc); results=[]
    try:
        for rule in db.scalars(select(AlertRule).where(AlertRule.enabled.is_(True))).all():
            try:
                if not croniter.match(rule.schedule_cron,now): continue
                owner=db.get(User,rule.owner_id); dataset=__import__('app.models.entities',fromlist=['Dataset']).Dataset
                ds=db.get(dataset,rule.dataset_id); result=execute_definition(db,owner,ds,rule.query_definition,max_rows=1)
                row=(result.get('rows') or [{}])[0]; value=next(iter(row.values()),0); rule.last_value=str(value)
                cooling=rule.last_triggered_at and rule.last_triggered_at+timedelta(minutes=rule.cooldown_minutes)>now
                if compare(value,rule.operator,rule.threshold) and not cooling:
                    msg=f'{rule.name}: valor {value} {rule.operator} limite {rule.threshold}'
                    delivery={}
                    if 'notification' in rule.channels:
                        for uid in rule.recipients: db.add(Notification(user_id=uid,title=rule.name,body=msg,level=rule.severity))
                        delivery['notification']='queued'
                    if 'message' in rule.channels:
                        for uid in rule.recipients: db.add(Message(sender_id=rule.owner_id,recipient_id=uid,subject=rule.name,body=msg))
                        delivery['message']='queued'
                    db.add(AlertEvent(rule_id=rule.id,value=str(value),message=msg,delivery_results=delivery)); rule.last_triggered_at=now
                    results.append(rule.id)
            except Exception as exc:
                db.add(AlertEvent(rule_id=rule.id,status='failed',message=str(exc)))
        db.commit(); return {'triggered':results}
    finally: db.close()
