package businessscope

import (
	"testing"
	"time"
)

func validCandidate(row int, vehicleID, customerID int64, vin string) Candidate {
	return Candidate{
		RowNumber: row, VehicleID: vehicleID, VehiclePresent: true, VIN: vin, PlateNumber: "沪A00001",
		CustomerID: customerID, CustomerPresent: true, CustomerProfileExists: true,
		ContractID: vehicleID + 1000, ContractPresent: true, ContractProfileExists: true,
		EffectiveCustomerID: customerID, EffectiveCustomerSet: true,
		ContractCode: "HT-1", ProjectName: "项目", OperationStatus: "1",
		ScopeStartAt: time.Date(2026, 7, 1, 8, 0, 0, 0, time.FixedZone("CST", 8*3600)),
	}
}

func TestBuildSnapshotClassifiesAndNormalizes(t *testing.T) {
	candidates := []Candidate{
		validCandidate(1, 10, 100, " lvin0001 "),
		func() Candidate {
			value := validCandidate(2, 11, 101, "LVIN0002")
			value.CustomerProfileExists = false
			return value
		}(),
		func() Candidate {
			value := validCandidate(3, 12, 102, "LVIN0003")
			value.EffectiveCustomerID = 999
			return value
		}(),
	}
	snapshot, err := BuildSnapshot(candidates, time.Now())
	if err != nil {
		t.Fatal(err)
	}
	if snapshot.Candidates != 3 || len(snapshot.Items) != 1 || len(snapshot.Rejections) != 2 {
		t.Fatalf("unexpected accounting: %#v", snapshot)
	}
	if snapshot.Items[0].VIN != "LVIN0001" {
		t.Fatalf("VIN not normalized: %q", snapshot.Items[0].VIN)
	}
	if snapshot.Rejections[0].ReasonCode != ReasonCustomerProfileMissing || snapshot.Rejections[1].ReasonCode != ReasonCustomerMismatch {
		t.Fatalf("unexpected reasons: %#v", snapshot.Rejections)
	}
}

func TestBuildSnapshotRejectsEveryDuplicateVehicle(t *testing.T) {
	snapshot, err := BuildSnapshot([]Candidate{
		validCandidate(1, 10, 100, "LVIN0001"),
		validCandidate(2, 10, 100, "LVIN0001"),
	}, time.Now())
	if err != nil {
		t.Fatal(err)
	}
	if len(snapshot.Items) != 0 || len(snapshot.Rejections) != 2 {
		t.Fatalf("duplicates must all be quarantined: %#v", snapshot)
	}
	for _, rejection := range snapshot.Rejections {
		if rejection.ReasonCode != ReasonDuplicateVehicle {
			t.Fatalf("unexpected duplicate reason: %#v", rejection)
		}
	}
}

func TestSnapshotVersionIsContentAddressed(t *testing.T) {
	first := []Candidate{validCandidate(1, 10, 100, "LVIN0001"), validCandidate(2, 11, 101, "LVIN0002")}
	second := []Candidate{first[1], first[0]}
	a, err := BuildSnapshot(first, time.Now())
	if err != nil {
		t.Fatal(err)
	}
	b, err := BuildSnapshot(second, time.Now().Add(time.Hour))
	if err != nil {
		t.Fatal(err)
	}
	if a.SourceVersion != b.SourceVersion || a.Checksum != b.Checksum {
		t.Fatalf("same content produced different versions: %s %s", a.SourceVersion, b.SourceVersion)
	}
}

func TestValidateSnapshotUsesCountAndRatioGates(t *testing.T) {
	snapshot := Snapshot{Candidates: 639, Items: make([]ScopeItem, 613), Rejections: make([]Rejection, 26)}
	if err := ValidateSnapshot(snapshot, 100, 0.10); err != nil {
		t.Fatalf("production baseline should pass: %v", err)
	}
	if err := ValidateSnapshot(snapshot, 20, 0.10); err == nil {
		t.Fatal("rejection count limit should fail")
	}
	if err := ValidateSnapshot(snapshot, 100, 0.01); err == nil {
		t.Fatal("rejection ratio limit should fail")
	}
}
