package mute

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"github.com/google/uuid"
	"github.com/jmoiron/sqlx"

	"github.com/tidbcloud/alertstore/pkg/subscription"
)

type Rule struct {
	ID        string          `db:"id" json:"id" validate:"required"`
	Filter    json.RawMessage `db:"filter" json:"filter" swaggertype:"object" validate:"required"`
	Reason    string          `db:"reason" json:"reason" validate:"required"`
	CreatedBy string          `db:"created_by" json:"created_by" validate:"required"`
	ExpiresAt time.Time       `db:"expires_at" json:"expires_at" validate:"required"`
	CreatedAt time.Time       `db:"created_at" json:"created_at" validate:"required"`
}

type Store struct {
	db *sqlx.DB
}

func NewStore(db *sqlx.DB) *Store {
	return &Store{db: db}
}

func (s *Store) Create(ctx context.Context, filter json.RawMessage, reason, createdBy string, expiresAt time.Time) (*Rule, error) {
	r := &Rule{
		ID:        uuid.New().String(),
		Filter:    filter,
		Reason:    reason,
		CreatedBy: createdBy,
		ExpiresAt: expiresAt,
	}

	const q = `
		INSERT INTO mute_rule (id, filter, reason, created_by, expires_at)
		VALUES (?, ?, ?, ?, ?)
	`
	_, err := s.db.ExecContext(ctx, q, r.ID, r.Filter, r.Reason, r.CreatedBy, r.ExpiresAt)
	if err != nil {
		return nil, fmt.Errorf("insert mute rule: %w", err)
	}
	return r, nil
}

func (s *Store) Get(ctx context.Context, id string) (*Rule, error) {
	const q = `SELECT * FROM mute_rule WHERE id = ?`
	var r Rule
	if err := s.db.GetContext(ctx, &r, q, id); err != nil {
		return nil, fmt.Errorf("get mute rule: %w", err)
	}
	return &r, nil
}

func (s *Store) Update(ctx context.Context, id string, filter json.RawMessage, reason string, expiresAt time.Time) error {
	const q = `UPDATE mute_rule SET filter = ?, reason = ?, expires_at = ? WHERE id = ?`
	res, err := s.db.ExecContext(ctx, q, filter, reason, expiresAt, id)
	if err != nil {
		return fmt.Errorf("update mute rule: %w", err)
	}
	n, _ := res.RowsAffected()
	if n == 0 {
		return fmt.Errorf("mute rule not found")
	}
	return nil
}

func (s *Store) Delete(ctx context.Context, id string) error {
	const q = `DELETE FROM mute_rule WHERE id = ?`
	_, err := s.db.ExecContext(ctx, q, id)
	return err
}

func (s *Store) ListActive(ctx context.Context) ([]Rule, error) {
	const q = `SELECT * FROM mute_rule WHERE expires_at > NOW(3) ORDER BY created_at DESC`
	var rules []Rule
	if err := s.db.SelectContext(ctx, &rules, q); err != nil {
		return nil, fmt.Errorf("list mute rules: %w", err)
	}
	return rules, nil
}

// IsMuted checks if the given alert attributes match any active mute rule.
func (s *Store) IsMuted(ctx context.Context, t subscription.Target) (*Rule, error) {
	rules, err := s.ListActive(ctx)
	if err != nil {
		return nil, err
	}

	for _, rule := range rules {
		var f subscription.SubscriptionFilter
		if err := json.Unmarshal(rule.Filter, &f); err != nil {
			continue
		}
		if f.Matches(t) {
			return &rule, nil
		}
	}
	return nil, nil
}
