"""
Notifications Router

Endpoints for notification log and email tests.
"""
from typing import Optional, List
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from sqlalchemy import desc
from pydantic import BaseModel

from app.database import get_db
from app.models.user import User
from app.models.notification_log import NotificationLog, NotificationType, NotificationStatus
from app.models.vulnerability import Vulnerability
from app.models.asset import Asset
from app.auth.dependencies import get_current_user, RequireAdmin
from app.services.email_service import send_email, get_smtp_config

router = APIRouter(prefix="/api/v1/notifications", tags=["Notifications"])


class NotificationLogResponse(BaseModel):
    id: int
    vulnerability_id: Optional[int]
    asset_id: Optional[int]
    user_id: Optional[int]
    notification_type: str
    sent_at: datetime
    subject: Optional[str]
    recipient_email: Optional[str]
    status: str
    error_message: Optional[str]
    cve_id: Optional[str] = None
    asset_hostname: Optional[str] = None
    username: Optional[str] = None
    message_body: Optional[str] = None

    class Config:
        from_attributes = True


class TestEmailRequest(BaseModel):
    to_email: str
    smtp_config: Optional[dict] = None


@router.get("/log", response_model=List[NotificationLogResponse])
async def list_notification_logs(
    notification_type: Optional[str] = Query(None),
    limit: int = Query(50, le=500),
    offset: int = Query(0),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """List notification history"""
    query = db.query(NotificationLog).order_by(desc(NotificationLog.sent_at))

    if notification_type:
        try:
            nt = NotificationType(notification_type)
            query = query.filter(NotificationLog.notification_type == nt)
        except ValueError:
            pass

    logs = query.offset(offset).limit(limit).all()

    results = []
    for log in logs:
        cve_id = None
        asset_hostname = None
        username = None

        if log.vulnerability:
            cve_id = log.vulnerability.cve_id
        if log.asset:
            asset_hostname = log.asset.hostname
        if log.user:
            username = log.user.username

        results.append({
            "id": log.id,
            "vulnerability_id": log.vulnerability_id,
            "asset_id": log.asset_id,
            "user_id": log.user_id,
            "notification_type": log.notification_type.value if log.notification_type else None,
            "sent_at": log.sent_at,
            "subject": log.subject,
            "recipient_email": log.recipient_email,
            "status": log.status.value if log.status else None,
            "error_message": log.error_message,
            "cve_id": cve_id,
            "asset_hostname": asset_hostname,
            "username": username,
            "message_body": log.message_body,
        })

    return results


@router.post("/test")
async def send_test_email(
    test_data: TestEmailRequest,
    db: Session = Depends(get_db),
    current_user: User = Depends(RequireAdmin)
):
    """Send a test email to verify SMTP configuration"""
    # Config Check (Override vs DB)
    config = test_data.smtp_config or get_smtp_config(db)
    if not config:
        raise HTTPException(status_code=400, detail="SMTP not configured")

    subject = "VulnCheck Dashboard - Test Email"
    body = """
    <html>
    <body style="font-family: Arial, sans-serif; padding: 20px;">
        <h2>SMTP Test Successful</h2>
        <p>This is a test email from VulnCheck Dashboard.</p>
        <p>Your SMTP configuration is working correctly.</p>
        <hr>
        <p style="color: #888; font-size: 12px;">Sent at: {}</p>
    </body>
    </html>
    """.format(datetime.now().strftime("%Y-%m-%d %H:%M:%S UTC"))

    success, message = send_email(db, test_data.to_email, subject, body, config_override=test_data.smtp_config)

    if success:
        return {"status": "ok", "message": f"Test email sent to {test_data.to_email}"}
    else:
        raise HTTPException(status_code=500, detail=f"Email sending failed: {message}")


@router.post("/notify-critical")
async def notify_unnotified_critical_vulnerabilities(
    db: Session = Depends(get_db),
    current_user: User = Depends(RequireAdmin)
):
    """
    Send notifications for all CRITICAL and HIGH vulnerabilities that have not yet received a notification.
    Useful for alerting about existing vulnerabilities after policy changes or initial setup.
    """
    try:
        from app.models.vulnerability import VulnerabilityStatus, VulnerabilitySeverity
        from app.services.email_service import send_new_vulnerability_notification
        from app.models.group import Group
        
        smtp_config = get_smtp_config(db)
        if not smtp_config:
            raise HTTPException(status_code=400, detail="SMTP not configured. Please save email settings first.")
        
        # Find all OPEN CRITICAL/HIGH vulnerabilities
        # Simplified query - we'll track notifications via the log entries
        unnotified_vulns = db.query(Vulnerability).join(Asset).filter(
            Vulnerability.status == VulnerabilityStatus.open,
            Vulnerability.severity.in_([VulnerabilitySeverity.critical])
        ).all()
        
        if not unnotified_vulns:
            return {"message": "No CRITICAL/HIGH vulnerabilities found.", "sent": 0, "failed": 0}
        
        sent_count = 0
        failed_count = 0
        
        for vuln in unnotified_vulns:
            asset = vuln.asset
            if not asset:
                continue
            
            # Get recipients from asset assignment
            recipients = []
            if asset.assigned_user_id:
                user = db.query(User).filter(User.id == asset.assigned_user_id).first()
                if user and user.email:
                    recipients.append((user.id, user.email, user.username))
            elif asset.groups:
                # Asset uses M2M groups (no single assigned_group_id column)
                for group in asset.groups:
                    for u in group.users:
                        if u.email:
                            recipients.append((u.id, u.email, u.username))
            
            if not recipients:
                # No recipients for this vulnerability's asset
                continue
            
            for r_uid, r_email, r_username in recipients:
                variables = {
                    "cve_id": vuln.cve_id,
                    "severity": vuln.severity.value,
                    "severity_upper": vuln.severity.value.upper(),
                    "cvss_score": str(vuln.cvss_score or "N/A"),
                    "asset_hostname": asset.hostname,
                    "asset_ip": asset.ip_address or "N/A",
                    "package_name": vuln.package_name or "N/A",
                    "title": vuln.title or "No description",
                    "description": vuln.title or "No description",
                    "detected_at": vuln.detected_at.strftime("%Y-%m-%d %H:%M UTC") if vuln.detected_at else "Unknown",
                    "dashboard_url": "https://your-vulncheck-instance.com/vulnerabilities",
                    "recipient_name": r_username,
                    "recipient_email": r_email
                }
                
                success, error_msg = send_new_vulnerability_notification(db, r_email, variables)
                
                # Log the notification (using MANUAL type as workaround until DB enum is updated)
                notif_log = NotificationLog(
                    vulnerability_id=vuln.id,
                    asset_id=asset.id,
                    user_id=r_uid,
                    notification_type=NotificationType.MANUAL,
                    sent_at=datetime.now(),
                    subject=f"[VULNCHECK] {vuln.severity.value.upper()} Vulnerability: {vuln.cve_id}",
                    recipient_email=r_email,
                    status=NotificationStatus.SENT if success else NotificationStatus.FAILED,
                    message_body=f"{vuln.severity.value} vulnerability {vuln.cve_id} on {asset.hostname}",
                    error_message=None if success else error_msg
                )
                db.add(notif_log)
                
                if success:
                    sent_count += 1
                else:
                    failed_count += 1
        
        db.commit()
        
        return {
            "message": f"Notifications sent for {len(unnotified_vulns)} vulnerabilities.",
            "sent": sent_count,
            "failed": failed_count
        }
    except HTTPException:
        raise
    except Exception as e:
        import traceback
        traceback.print_exc()
        raise HTTPException(status_code=500, detail=f"Error sending: {str(e)}")
