from fastapi import APIRouter, Depends, HTTPException, Query, Request
from sqlalchemy import or_
from sqlalchemy.orm import Session
from typing import List, Optional
from datetime import datetime

from ..database import get_db
from ..models import Notification, NotificationPreference, User, SystemSetting
from ..schemas import NotificationOut, NotificationPreferenceUpdate, NotificationPreferenceOut
from ..dependencies import get_current_user, require_owner

router = APIRouter()


def _user_notifications_query(db: Session, user: User):
    """Query notifications visible to this user (personal + role-broadcast)."""
    return db.query(Notification).filter(
        or_(
            Notification.user_id == user.id,
            Notification.user_id.is_(None),
            Notification.target_role == 'ALL',
            Notification.target_role == user.role,
        )
    )


@router.get("/notifications", response_model=List[NotificationOut])
def list_notifications(
    db: Session = Depends(get_db),
    user=Depends(get_current_user),
):
    return (
        _user_notifications_query(db, user)
        .order_by(Notification.is_read.asc(), Notification.created_at.desc())
        .limit(100)
        .all()
    )


@router.get("/notifications/count")
def notification_count(
    db: Session = Depends(get_db),
    user=Depends(get_current_user),
):
    count = (
        _user_notifications_query(db, user)
        .filter(Notification.is_read == False)
        .count()
    )
    return {"unread": count}


@router.put("/notifications/{notif_id}/read")
def mark_read(
    notif_id: int,
    db: Session = Depends(get_db),
    _=Depends(get_current_user),
):
    n = db.query(Notification).filter(Notification.id == notif_id).first()
    if not n:
        raise HTTPException(404, "Notification not found")
    n.is_read = True
    n.read_at = datetime.utcnow()
    db.commit()
    return {"ok": True}


@router.put("/notifications/read-all")
def mark_all_read(
    db: Session = Depends(get_db),
    user=Depends(get_current_user),
):
    rows = _user_notifications_query(db, user).filter(Notification.is_read == False).all()
    now = datetime.utcnow()
    for n in rows:
        n.is_read = True
        n.read_at = now
    db.commit()
    return {"ok": True, "marked": len(rows)}


@router.delete("/notifications/{notif_id}")
def dismiss_notification(
    notif_id: int,
    db: Session = Depends(get_db),
    _=Depends(get_current_user),
):
    n = db.query(Notification).filter(Notification.id == notif_id).first()
    if not n:
        raise HTTPException(404, "Notification not found")
    db.delete(n)
    db.commit()
    return {"ok": True}


@router.get("/notification-preferences", response_model=NotificationPreferenceOut)
def get_prefs(
    db: Session = Depends(get_db),
    user=Depends(get_current_user),
):
    prefs = db.query(NotificationPreference).filter(
        NotificationPreference.user_id == user.id
    ).first()
    if not prefs:
        # Return defaults without persisting
        return NotificationPreferenceOut(
            user_id=user.id,
            email_enabled=False,
            email=None,
            whatsapp_enabled=False,
            whatsapp_number=None,
            alert_unclosed_shift=True,
            alert_credit_limit=True,
            alert_low_stock=True,
            alert_price_override=True,
        )
    return prefs


@router.put("/notification-preferences", response_model=NotificationPreferenceOut)
def update_prefs(
    body: NotificationPreferenceUpdate,
    db: Session = Depends(get_db),
    user=Depends(get_current_user),
):
    prefs = db.query(NotificationPreference).filter(
        NotificationPreference.user_id == user.id
    ).first()
    if not prefs:
        prefs = NotificationPreference(user_id=user.id)
        db.add(prefs)
    for k, v in body.model_dump(exclude_none=True).items():
        setattr(prefs, k, v)
    db.commit()
    db.refresh(prefs)
    return prefs


@router.post("/notifications/test-email")
def test_email(
    db: Session = Depends(get_db),
    user=Depends(require_owner),
):
    """Send a test email using the current SMTP settings stored in DB."""
    from ..services.notification_service import _send_email, _get_setting
    smtp_host  = _get_setting(db, 'smtp_host')
    from_email = _get_setting(db, 'smtp_from_email')
    to_email   = _get_setting(db, 'smtp_to_email') or from_email
    if not smtp_host:
        raise HTTPException(400, "SMTP host not configured. Save SMTP settings first.")
    if not to_email:
        raise HTTPException(400, "To Email not configured.")
    try:
        _send_email(
            db,
            to_email=to_email,
            title="Test Email — Dunhinda Brothers Fuel Station",
            message=(
                "This is a test email from your Fuel Station Management System.\n\n"
                "If you received this, SMTP is configured correctly."
            ),
        )
        return {"ok": True, "sent_to": to_email}
    except Exception as e:
        raise HTTPException(500, f"Email send failed: {e}")


@router.post("/notifications/check-alerts")
def run_checks(
    request: Request,
    cron_key: Optional[str] = Query(None),
    db: Session = Depends(get_db),
):
    """Run alert checks. Auth: Bearer token (OWNER/SUPER_ADMIN) OR valid cron_key param."""
    from ..auth import decode_token
    from jose import JWTError

    authed = False
    auth_header = request.headers.get('Authorization', '')
    if auth_header.startswith('Bearer '):
        try:
            payload = decode_token(auth_header[7:])
            user = db.query(User).filter(
                User.id == int(payload.get('sub', 0)),
                User.is_active == True,
                User.role.in_(['OWNER', 'SUPER_ADMIN']),
            ).first()
            if user:
                authed = True
        except (JWTError, Exception):
            pass

    if not authed and cron_key:
        setting = db.query(SystemSetting).filter(
            SystemSetting.setting_key == 'notifications_cron_key'
        ).first()
        expected = setting.setting_value if setting else ''
        if expected and cron_key == expected:
            authed = True

    if not authed:
        raise HTTPException(status_code=401, detail='Unauthorized — provide Bearer token or valid cron_key')

    from ..services.notification_service import (
        check_unclosed_shifts, check_credit_limits, check_low_stock,
    )
    results = {}
    try:
        results['unclosed_shifts'] = check_unclosed_shifts(db)
    except Exception as e:
        results['unclosed_shifts_error'] = str(e)
    try:
        results['credit_limits'] = check_credit_limits(db)
    except Exception as e:
        results['credit_limits_error'] = str(e)
    try:
        results['low_stock'] = check_low_stock(db)
    except Exception as e:
        results['low_stock_error'] = str(e)
    return results
