package service

import (
	"testing"

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

	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

func setupManagerRulesTestDB(t *testing.T) {
	t.Helper()

	var err error
	db.DB, err = gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	if err != nil {
		t.Fatalf("failed to connect sqlite: %v", err)
	}

	err = db.DB.AutoMigrate(&models.Team{}, &models.Engineer{}, &models.EngineerTeam{}, &models.SuperAdmin{})
	if err != nil {
		t.Fatalf("failed to migrate: %v", err)
	}

	t.Setenv("AUTH0_ENABLED", "false")
	t.Setenv("DEV_BYPASS_AUTH", "false")
	t.Setenv("ALLOWED_EMAIL_DOMAINS", "pingcap.com")
	t.Setenv("FEISHU_APP_ID", "")
	t.Setenv("FEISHU_APP_SECRET", "")
}

func TestRemoveManagerFromTeamByEmail_RejectsLastManager(t *testing.T) {
	setupManagerRulesTestDB(t)

	cat := models.Team{Name: "team_alpha", DisplayName: "Team Alpha"}
	if err := db.DB.Create(&cat).Error; err != nil {
		t.Fatalf("create team: %v", err)
	}
	eng := models.Engineer{Name: "Owner", Email: "owner@pingcap.com"}
	if err := db.DB.Create(&eng).Error; err != nil {
		t.Fatalf("create engineer: %v", err)
	}
	if err := db.DB.Create(&models.EngineerTeam{EngineerID: eng.ID, TeamID: cat.ID, Role: models.TeamRoleManager}).Error; err != nil {
		t.Fatalf("create manager link: %v", err)
	}

	s := &ScheduleService{}
	if err := s.RemoveManagerFromTeamByEmail("owner@pingcap.com", cat.ID); err == nil {
		t.Fatalf("expected error when removing last manager")
	}

	var rel models.EngineerTeam
	if err := db.DB.Where("engineer_id = ? AND team_id = ?", eng.ID, cat.ID).First(&rel).Error; err != nil {
		t.Fatalf("query relation: %v", err)
	}
	if !rel.HasRole(models.TeamRoleManager) {
		t.Fatalf("expected manager role to remain")
	}
}

func TestRemoveManagerFromTeamByEmail_RejectsLastDistinctManagerWithDuplicateRelations(t *testing.T) {
	setupManagerRulesTestDB(t)

	cat := models.Team{Name: "team_gamma", DisplayName: "Team Gamma"}
	if err := db.DB.Create(&cat).Error; err != nil {
		t.Fatalf("create team: %v", err)
	}
	eng := models.Engineer{Name: "Owner", Email: "owner@pingcap.com"}
	if err := db.DB.Create(&eng).Error; err != nil {
		t.Fatalf("create engineer: %v", err)
	}
	if err := db.DB.Create(&models.EngineerTeam{EngineerID: eng.ID, TeamID: cat.ID, Role: models.TeamRoleManager}).Error; err != nil {
		t.Fatalf("create first manager link: %v", err)
	}
	if err := db.DB.Create(&models.EngineerTeam{EngineerID: eng.ID, TeamID: cat.ID, Role: models.TeamRoleManager}).Error; err != nil {
		t.Fatalf("create duplicate manager link: %v", err)
	}

	s := &ScheduleService{}
	if err := s.RemoveManagerFromTeamByEmail("owner@pingcap.com", cat.ID); err == nil {
		t.Fatalf("expected error when removing last distinct manager")
	}

	var count int64
	if err := db.DB.Model(&models.EngineerTeam{}).Where("engineer_id = ? AND team_id = ? AND role = ?", eng.ID, cat.ID, models.TeamRoleManager).Count(&count).Error; err != nil {
		t.Fatalf("count manager relations: %v", err)
	}
	if count != 2 {
		t.Fatalf("expected duplicate manager relations to remain, got %d", count)
	}
}

func TestAddManagerToTeamByEmail_ValidatesEmailDomain(t *testing.T) {
	setupManagerRulesTestDB(t)

	cat := models.Team{Name: "team_beta", DisplayName: "Team Beta"}
	if err := db.DB.Create(&cat).Error; err != nil {
		t.Fatalf("create team: %v", err)
	}

	s := &ScheduleService{}
	if err := s.AddManagerToTeamByEmail("user@example.com", cat.ID); err == nil {
		t.Fatalf("expected invalid domain to be rejected")
	}
}

func TestTeamManagerEmails_SortedAndManagersOnly(t *testing.T) {
	setupManagerRulesTestDB(t)

	cat := models.Team{Name: "team_beta", DisplayName: "Team Beta"}
	if err := db.DB.Create(&cat).Error; err != nil {
		t.Fatalf("create team: %v", err)
	}
	other := models.Team{Name: "team_gamma", DisplayName: "Team Gamma"}
	if err := db.DB.Create(&other).Error; err != nil {
		t.Fatalf("create other team: %v", err)
	}

	links := []struct {
		name   string
		email  string
		teamID uint
		role   string
	}{
		{"Zoe", "Zoe@pingcap.com", cat.ID, models.TeamRoleManager},
		{"Amy", "amy@pingcap.com", cat.ID, models.TeamRoleManager},
		{"Editor", "editor@pingcap.com", cat.ID, models.TeamRoleEditor},
		{"Member", "member@pingcap.com", cat.ID, models.TeamRoleMember},
		{"Outsider", "outsider@pingcap.com", other.ID, models.TeamRoleManager},
	}
	for _, l := range links {
		eng := models.Engineer{Name: l.name, Email: l.email}
		if err := db.DB.Create(&eng).Error; err != nil {
			t.Fatalf("create engineer %s: %v", l.email, err)
		}
		if err := db.DB.Create(&models.EngineerTeam{EngineerID: eng.ID, TeamID: l.teamID, Role: l.role}).Error; err != nil {
			t.Fatalf("create link %s: %v", l.email, err)
		}
	}

	s := &ScheduleService{}
	got, err := s.TeamManagerEmails(cat.ID)
	if err != nil {
		t.Fatalf("TeamManagerEmails: %v", err)
	}
	want := []string{"amy@pingcap.com", "zoe@pingcap.com"}
	if len(got) != len(want) {
		t.Fatalf("got %v, want %v", got, want)
	}
	for i := range want {
		if got[i] != want[i] {
			t.Fatalf("got %v, want %v", got, want)
		}
	}
}

func TestTeamManagerEmails_EmptyWhenNoManagers(t *testing.T) {
	setupManagerRulesTestDB(t)

	cat := models.Team{Name: "team_delta", DisplayName: "Team Delta"}
	if err := db.DB.Create(&cat).Error; err != nil {
		t.Fatalf("create team: %v", err)
	}

	s := &ScheduleService{}
	got, err := s.TeamManagerEmails(cat.ID)
	if err != nil {
		t.Fatalf("TeamManagerEmails: %v", err)
	}
	if len(got) != 0 {
		t.Fatalf("expected no managers, got %v", got)
	}
}
