package meta

import (
	"context"
	"testing"
	"time"
)

func TestBillingOpsDeltaInsertSumAndPrune(t *testing.T) {
	s := newControlStore(t)
	ctx := context.Background()

	base := time.Date(2026, 9, 3, 10, 0, 0, 0, time.UTC)
	end := base.Add(time.Hour)
	rows := []BillingOpsDelta{
		{TenantID: "t1", OrgID: "42", Direction: "read", TrafficPath: "db9", Ops: 3, Cumulative: 100},
		{TenantID: "t1", OrgID: "42", Direction: "read", TrafficPath: "s3", Ops: 2, Cumulative: 50},
		{TenantID: "t1", OrgID: "42", Direction: "write", TrafficPath: "db9", Ops: 1, Cumulative: 7},
		{TenantID: "t2", OrgID: "7", Direction: "read", TrafficPath: "db9", Ops: 9, Cumulative: 9},
	}
	if err := s.InsertBillingOpsDeltas(ctx, "pod-a", base.Add(10*time.Minute), rows); err != nil {
		t.Fatalf("insert deltas: %v", err)
	}
	// A retried flush re-inserts the same cumulative points: INSERT IGNORE on
	// the (pod, series, cumulative) key keeps it at-most-once.
	if err := s.InsertBillingOpsDeltas(ctx, "pod-a", base.Add(10*time.Minute), rows); err != nil {
		t.Fatalf("retry insert deltas: %v", err)
	}
	var rowCount int
	if err := s.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM billing_ops_delta`).Scan(&rowCount); err != nil {
		t.Fatal(err)
	}
	if rowCount != len(rows) {
		t.Fatalf("rows = %d, want %d (retry must not duplicate)", rowCount, len(rows))
	}

	// The same cumulative point under a different tenant generation (series
	// evicted and restarted) is a legitimate new row, not a duplicate.
	if err := s.InsertBillingOpsDeltas(ctx, "pod-a", base.Add(10*time.Minute), []BillingOpsDelta{
		{TenantID: "t1", OrgID: "42", Direction: "read", TrafficPath: "db9", Ops: 4, Cumulative: 100, Gen: 1},
	}); err != nil {
		t.Fatalf("insert next-gen delta: %v", err)
	}
	if err := s.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM billing_ops_delta`).Scan(&rowCount); err != nil {
		t.Fatal(err)
	}
	if rowCount != len(rows)+1 {
		t.Fatalf("rows = %d, want %d (next generation must persist)", rowCount, len(rows)+1)
	}
	// Invalid rows are rejected.
	if err := s.InsertBillingOpsDeltas(ctx, "pod-a", base, []BillingOpsDelta{{TenantID: "", Ops: 1}}); err == nil {
		t.Fatal("expected validation error for empty tenant")
	}

	sums, err := s.SumBillingOpsDeltas(ctx, base, end)
	if err != nil {
		t.Fatalf("sum deltas: %v", err)
	}
	// traffic_path is a billing dimension: db9 and s3 reads stay separate.
	if len(sums) != 4 {
		t.Fatalf("sums = %+v, want 4 groups", sums)
	}
	byKey := map[string]int64{}
	for _, sum := range sums {
		byKey[sum.TenantID+"/"+sum.Direction+"/"+sum.TrafficPath] = sum.Ops
	}
	// The next-generation row (ops=4) joins the same read/db9 group.
	if byKey["t1/read/db9"] != 7 || byKey["t1/read/s3"] != 2 || byKey["t1/write/db9"] != 1 || byKey["t2/read/db9"] != 9 {
		t.Fatalf("sums = %v", byKey)
	}

	// Range boundaries are [from, to).
	sums, err = s.SumBillingOpsDeltas(ctx, base.Add(30*time.Minute), end)
	if err != nil {
		t.Fatal(err)
	}
	if len(sums) != 0 {
		t.Fatalf("sums outside range = %+v, want none", sums)
	}

	deleted, err := s.DeleteBillingOpsDeltasBefore(ctx, end)
	if err != nil {
		t.Fatalf("prune: %v", err)
	}
	if deleted != int64(len(rows)+1) {
		t.Fatalf("deleted = %d, want %d", deleted, len(rows)+1)
	}
	sums, err = s.SumBillingOpsDeltas(ctx, base, end)
	if err != nil {
		t.Fatal(err)
	}
	if len(sums) != 0 {
		t.Fatalf("sums after prune = %+v, want none", sums)
	}
}
