package repository

import (
	"context"

	"gorm.io/gorm"

	"git.jabali-panel.com/shukivaknin/jabali2/panel-api/internal/models"
)

// MalwareEventListFilter narrows ListEvents results.
type MalwareEventListFilter struct {
	Source   string // "" = any
	Severity string // "" = any
	UserID   string // "" = any
	Limit    int
	Offset   int
}

// MalwareEventRepository owns the malware_events table (M33). Inserts
// happen via the loopback ingest endpoint; reads serve the Recent
// Events card and the M14 dispatcher (NotifyEnvelopes pulls notified=0).
type MalwareEventRepository interface {
	Create(ctx context.Context, ev *models.MalwareEvent) error
	List(ctx context.Context, f MalwareEventListFilter) ([]models.MalwareEvent, int64, error)
	ListUnnotified(ctx context.Context, limit int) ([]models.MalwareEvent, error)
	MarkNotified(ctx context.Context, id string) error
	Counts24h(ctx context.Context) (hits int64, quarantined int64, err error)
}

type malwareEventRepo struct{ db *gorm.DB }

// NewMalwareEventRepository returns a GORM-backed event repo.
func NewMalwareEventRepository(db *gorm.DB) MalwareEventRepository {
	return &malwareEventRepo{db: db}
}

func (r *malwareEventRepo) Create(ctx context.Context, ev *models.MalwareEvent) error {
	if err := r.db.WithContext(ctx).Create(ev).Error; err != nil {
		return translate(err)
	}
	return nil
}

func (r *malwareEventRepo) List(ctx context.Context, f MalwareEventListFilter) ([]models.MalwareEvent, int64, error) {
	q := r.db.WithContext(ctx).Model(&models.MalwareEvent{})
	if f.Source != "" {
		q = q.Where("source = ?", f.Source)
	}
	if f.Severity != "" {
		q = q.Where("severity = ?", f.Severity)
	}
	if f.UserID != "" {
		q = q.Where("user_id = ?", f.UserID)
	}
	var total int64
	if err := q.Count(&total).Error; err != nil {
		return nil, 0, translate(err)
	}
	limit := f.Limit
	if limit <= 0 {
		limit = 100
	}
	var out []models.MalwareEvent
	if err := q.Order("created_at DESC").Limit(limit).Offset(f.Offset).Find(&out).Error; err != nil {
		return nil, 0, translate(err)
	}
	return out, total, nil
}

func (r *malwareEventRepo) ListUnnotified(ctx context.Context, limit int) ([]models.MalwareEvent, error) {
	if limit <= 0 {
		limit = 100
	}
	var out []models.MalwareEvent
	if err := r.db.WithContext(ctx).
		Where("notified = 0").
		Order("created_at ASC").
		Limit(limit).
		Find(&out).Error; err != nil {
		return nil, translate(err)
	}
	return out, nil
}

func (r *malwareEventRepo) MarkNotified(ctx context.Context, id string) error {
	res := r.db.WithContext(ctx).
		Model(&models.MalwareEvent{}).
		Where("id = ?", id).
		Update("notified", 1)
	if res.Error != nil {
		return translate(res.Error)
	}
	return nil
}

// Counts24h returns counts for the realtime monitor card.
//   - hits: malware_events rows in last 24h
//   - quarantined: malware_quarantine rows detected in last 24h
//     (active OR historical — operator wants the whole picture)
func (r *malwareEventRepo) Counts24h(ctx context.Context) (int64, int64, error) {
	var hits, q int64
	if err := r.db.WithContext(ctx).
		Model(&models.MalwareEvent{}).
		Where("created_at >= NOW() - INTERVAL 1 DAY").
		Count(&hits).Error; err != nil {
		return 0, 0, translate(err)
	}
	if err := r.db.WithContext(ctx).
		Model(&models.MalwareQuarantine{}).
		Where("detected_at >= NOW() - INTERVAL 1 DAY").
		Count(&q).Error; err != nil {
		return 0, 0, translate(err)
	}
	return hits, q, nil
}
