package classify

import (
	"context"
	"log/slog"
	"time"

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

// CustomerService checks if a tenant is a KA customer.
type CustomerService interface {
	IsKA(ctx context.Context, tenantID string) (bool, error)
}

// ClinicService applies the legacy jiralert ActivityHub precheck.
type ClinicService interface {
	HasRelatedActivity(ctx context.Context, alertname, clusterID string, observedAt time.Time) (bool, error)
}

type Classifier struct {
	customer CustomerService
	clinic   ClinicService
	logger   *slog.Logger
}

func New(customer CustomerService, clinic ClinicService, logger *slog.Logger) *Classifier {
	return &Classifier{
		customer: customer,
		clinic:   clinic,
		logger:   logger,
	}
}

// Result holds the classification outcome.
type Result struct {
	Classification string // page / ticket / logging
	Original       string // before override
	Reason         string // why it was overridden (empty if not)
}

// Classify determines the final classification for an alert.
// The base classification comes from alertmanager rule labels.
// Three override layers may downgrade it.
func (c *Classifier) Classify(
	ctx context.Context,
	alertname,
	classification,
	visibility,
	tenantID,
	clusterID string,
	observedAt time.Time,
) Result {
	original := classification

	// Override 0: a customer-facing rule is never an internal response.
	//
	// Its notification has already gone to the customer, on Alertmanager's
	// schedule; what reaches us is a copy. Paging an on-caller for it would be
	// the second notification for one condition and would put the person on the
	// hook for something the customer is already handling — and because these
	// rules carry no response_class, the severity fallback would do exactly
	// that for every critical one.
	//
	// It runs first and returns outright: this is a property of who the rule
	// was written for, so no later layer can raise it back. Delivery to
	// interested channels is a subscription concern (see the notice path), not
	// a classification one.
	if visibility == alert.VisibilityExternal {
		return Result{
			Classification: alert.ClassLogging,
			Original:       original,
			Reason:         "external_visibility",
		}
	}

	// Override 1: non-KA customer filter
	if c.customer != nil && tenantID != "" && shouldCheckKA(alertname) {
		isKA, err := c.customer.IsKA(ctx, tenantID)
		if err != nil {
			c.logger.Error("check KA status", "err", err, "tenant_id", tenantID)
			// On error, don't override — keep original classification.
		} else if !isKA {
			return Result{
				Classification: alert.ClassLogging,
				Original:       original,
				Reason:         "non_ka_customer",
			}
		}
	}

	// Override 2: a related recent operational activity covered by jiralert's
	// legacy EVENT precheck downgrades page to ticket.
	if c.clinic != nil && classification == alert.ClassPage && clusterID != "" {
		hasActivity, err := c.clinic.HasRelatedActivity(ctx, alertname, clusterID, observedAt)
		if err != nil {
			c.logger.Error("check clinic activity", "err", err, "cluster_id", clusterID)
		} else if hasActivity {
			return Result{
				Classification: alert.ClassTicket,
				Original:       original,
				Reason:         "recent_activity",
			}
		}
	}

	return Result{
		Classification: classification,
		Original:       original,
	}
}

// shouldCheckKA returns true if this alertname should be filtered for non-KA customers.
// Hardcoded list — add/remove by changing code and deploying.
func shouldCheckKA(alertname string) bool {
	switch alertname {
	case "TiKVInstanceLowSpace",
		"KubePersistentVolumeFillingUp":
		return true
	default:
		return false
	}
}
