package service

import (
	"testing"

	"github.com/tidbcloud/aisupport/services/oncall/db"
	"github.com/tidbcloud/aisupport/services/oncall/models"
)

func mkEngineer(t *testing.T, name, email string) uint {
	t.Helper()
	e := models.Engineer{Name: name, Email: email}
	if err := db.DB.Create(&e).Error; err != nil {
		t.Fatal(err)
	}
	return e.ID
}

func TestEffectiveV2BaselineAndOverride(t *testing.T) {
	newTestDB(t)
	cat := models.Team{Name: "team", DisplayName: "team"}
	db.DB.Create(&cat)
	mkEngineer(t, "Alice", "a@x.com")
	mkEngineer(t, "Bob", "b@x.com")
	mkEngineer(t, "Carol", "c@x.com")
	dID := mkEngineer(t, "Dave", "d@x.com")

	db.DB.Create(&models.TeamLayer{
		TeamID: cat.ID, Priority: 1,
		People:             models.StringList{"a@x.com", "b@x.com", "c@x.com"},
		RotateEverySeconds: week, OnCallAtOnce: 1, ActiveMode: "always",
		StartsAt: monday00(),
	})

	s := &ScheduleService{}

	// Pure baseline over 3 weeks: a, b, c.
	rows, err := s.GetEffectiveScheduleV2([]uint{cat.ID}, monday00(), monday00()+3*week, false, false)
	if err != nil {
		t.Fatal(err)
	}
	if len(rows) != 3 {
		t.Fatalf("want 3 baseline rows, got %d: %+v", len(rows), rows)
	}
	wantEmails := []string{"a@x.com", "b@x.com", "c@x.com"}
	for i, r := range rows {
		if r["engineer_email"] != wantEmails[i] || r["overlay"].(int) != 0 {
			t.Fatalf("row %d = %v", i, r)
		}
	}

	// Override [Mon 02:00, Mon 04:00) -> Dave (overlay 1) wins in that slice.
	db.DB.Create(&models.ShiftInterval{
		TeamID: cat.ID, EngineerID: dID,
		StartTime: monday00() + 2*3600, EndTime: monday00() + 4*3600,
		Overlay: 1, IsBackup: false, SourceType: "manual-edit",
	})
	rows, _ = s.GetEffectiveScheduleV2([]uint{cat.ID}, monday00(), monday00()+week, false, false)
	var sawDave bool
	for _, r := range rows {
		if r["engineer_email"] == "d@x.com" {
			sawDave = true
			if r["start_time"].(int64) != monday00()+2*3600 || r["end_time"].(int64) != monday00()+4*3600 {
				t.Fatalf("override window wrong: %v", r)
			}
			if r["overlay"].(int) != 1 {
				t.Fatalf("override overlay wrong: %v", r)
			}
		}
	}
	if !sawDave {
		t.Fatalf("override did not win, rows: %+v", rows)
	}

	// Clearing override (no engineer) -> no rows in that window.
	db.DB.Create(&models.ShiftInterval{
		TeamID: cat.ID, EngineerID: 0,
		StartTime: monday00() + 10*3600, EndTime: monday00() + 12*3600,
		Overlay: 2, IsBackup: false, SourceType: "manual-edit",
	})
	rows, _ = s.GetEffectiveScheduleV2([]uint{cat.ID}, monday00()+10*3600, monday00()+12*3600, false, false)
	if len(rows) != 0 {
		t.Fatalf("clearing override should yield no rows, got %+v", rows)
	}
}

func TestRemoveOverlayRangeRevertsToBaseline(t *testing.T) {
	newTestDB(t)
	team := models.Team{Name: "t", DisplayName: "t"}
	db.DB.Create(&team)
	mkEngineer(t, "Alice", "a@x.com")
	dID := mkEngineer(t, "Dave", "d@x.com")
	db.DB.Create(&models.TeamLayer{
		TeamID: team.ID, Priority: 1, People: models.StringList{"a@x.com"},
		RotateEverySeconds: week, OnCallAtOnce: 1, ActiveMode: "always", StartsAt: monday00(),
	})
	db.DB.Create(&models.ShiftInterval{
		TeamID: team.ID, EngineerID: dID,
		StartTime: monday00() + 2*3600, EndTime: monday00() + 4*3600,
		Overlay: 1, SourceType: "manual-edit",
	})
	s := &ScheduleService{}

	n, err := s.RemoveOverlayRange(team.ID, monday00()+2*3600, monday00()+4*3600, false)
	if err != nil || n != 1 {
		t.Fatalf("remove: n=%d err=%v", n, err)
	}
	rows, _ := s.GetEffectiveScheduleV2([]uint{team.ID}, monday00(), monday00()+week, false, false)
	for _, r := range rows {
		if r["engineer_email"] == "d@x.com" {
			t.Fatalf("override should be gone, got %+v", rows)
		}
	}
}

// The overview needs each on-call row to carry the engineer's English name so the
// UI can show name + en_name together; verify GetEffectiveScheduleV2 emits it.
func TestEffectiveIncludesEnName(t *testing.T) {
	newTestDB(t)
	s := &ScheduleService{}
	team := models.Team{Name: "t", DisplayName: "T"}
	db.DB.Create(&team)
	db.DB.Create(&models.Engineer{Name: "胡雯", EnName: "Wen Hu", Email: "wen.hu@x.com"})
	db.DB.Create(&models.TeamLayer{TeamID: team.ID, Priority: 1, People: models.StringList{"wen.hu@x.com"},
		OnCallAtOnce: 1, ActiveMode: "always"})

	now := monday00() + 6*3600
	rows, err := s.GetEffectiveScheduleV2([]uint{team.ID}, now, now+1, false, false)
	if err != nil {
		t.Fatal(err)
	}
	if len(rows) == 0 {
		t.Fatal("expected at least one row")
	}
	if got, _ := rows[0]["engineer_en_name"].(string); got != "Wen Hu" {
		t.Fatalf("engineer_en_name should be 'Wen Hu', got %q", got)
	}
}
