package presets

import (
	"io/fs"
	"reflect"
	"strings"
	"testing"
)

func templateBySlug(t *testing.T, templates []TeamTemplate, slug string) TeamTemplate {
	t.Helper()
	for _, template := range templates {
		if template.Slug == slug {
			return template
		}
	}
	t.Fatalf("template %q not found", slug)
	return TeamTemplate{}
}

func TestLoadTeamTemplates_DefaultLocale(t *testing.T) {
	templates, err := LoadTeamTemplates("")
	if err != nil {
		t.Fatalf("LoadTeamTemplates: %v", err)
	}
	if len(templates) != 6 {
		t.Fatalf("expected 6 built-in templates, got %d", len(templates))
	}
	wantSlugs := []string{
		"bug-hunt-regression-fix",
		"code-review-board",
		"decision-memo-crew",
		"feature-dev-squad",
		"incident-triage-room",
		"knowledge-builder",
	}
	for i, want := range wantSlugs {
		if templates[i].Slug != want {
			t.Errorf("templates[%d].Slug = %q, want %q", i, templates[i].Slug, want)
		}
	}
	for _, template := range templates {
		if template.ID == "" {
			t.Errorf("template %q missing ID", template.Slug)
		}
		if template.Name == "" || template.Name == template.Slug {
			t.Errorf("template %q missing localized Name (got %q)", template.Slug, template.Name)
		}
		if template.Description == "" {
			t.Errorf("template %q missing English description", template.Slug)
		}
		if _, ok := reflect.TypeOf(template).FieldByName("Team" + "Prompt"); ok {
			t.Errorf("template %q still exposes the retired duty field", template.Slug)
		}
		if template.Visibility != "workspace" {
			t.Errorf("template %q visibility = %q, want workspace", template.Slug, template.Visibility)
		}
		if template.Scope != "workspace" {
			t.Errorf("template %q scope = %q, want workspace", template.Slug, template.Scope)
		}
		if len(template.Members) == 0 {
			t.Errorf("template %q has no members", template.Slug)
		}
		for _, member := range template.Members {
			if member.ID == "" {
				t.Errorf("template %q has member with empty ID", template.Slug)
			}
			if member.ActorKind == "" {
				t.Errorf("template %q member %q missing actor_kind", template.Slug, member.ID)
			}
			if member.RoleLabel == "" {
				t.Errorf("template %q member %q missing English role_label", template.Slug, member.ID)
			}
			if member.RoleOverlayPrompt == "" {
				t.Errorf("template %q member %q missing English role_overlay_prompt", template.Slug, member.ID)
			}
		}
	}
}

func TestBuiltInTeamTemplatesUseDescriptionAsTheOnlyTeamDuty(t *testing.T) {
	err := fs.WalkDir(teamPresetFS, teamPresetRoot, func(path string, entry fs.DirEntry, err error) error {
		if err != nil {
			return err
		}
		if entry.IsDir() || entry.Name() != teamTemplateFile {
			return nil
		}
		raw, err := teamPresetFS.ReadFile(path)
		if err != nil {
			return err
		}
		if strings.Contains(string(raw), "team_"+"prompt:") {
			t.Errorf("%s still declares the retired duty key", path)
		}
		return nil
	})
	if err != nil {
		t.Fatalf("walk built-in team templates: %v", err)
	}
}

func TestBuiltInTeamTemplatesDeclareOneClearLeader(t *testing.T) {
	templates, err := LoadTeamTemplates("")
	if err != nil {
		t.Fatalf("LoadTeamTemplates: %v", err)
	}

	wantLeaders := map[string]string{
		"bug-hunt-regression-fix": "btm_bug_hunt_root_cause",
		"code-review-board":       "btm_code_review_correctness",
		"decision-memo-crew":      "btm_decision_researcher",
		"feature-dev-squad":       "btm_feature_dev_squad_lead",
		"incident-triage-room":    "btm_incident_mitigation",
		"knowledge-builder":       "btm_knowledge_structure_editor",
	}
	for _, template := range templates {
		wantLeader, ok := wantLeaders[template.Slug]
		if !ok {
			t.Fatalf("template %q missing expected leader", template.Slug)
		}
		var gotLeaders []string
		for _, member := range template.Members {
			if member.Role == "leader" {
				gotLeaders = append(gotLeaders, member.ID)
			} else if member.Role != "" {
				t.Fatalf("template %q member %q declares unsupported role %q", template.Slug, member.ID, member.Role)
			}
		}
		if len(gotLeaders) != 1 || gotLeaders[0] != wantLeader {
			t.Fatalf("template %q leaders = %v, want [%s]", template.Slug, gotLeaders, wantLeader)
		}
	}
}

type teamTemplateRoleMetadata struct {
	PresetID              string
	PresetVersion         string
	RoleRequired          bool
	RoleRealizationPolicy string
}

func TestLoadTeamTemplatesRoleMetadata(t *testing.T) {
	templates, err := LoadTeamTemplates("")
	if err != nil {
		t.Fatalf("LoadTeamTemplates: %v", err)
	}

	want := map[string]map[string]teamTemplateRoleMetadata{
		"feature-dev-squad": {
			"btm_feature_dev_squad_lead":     {PresetID: "project-coordinator", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
			"btm_feature_dev_squad_frontend": {PresetID: "frontend-developer", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
			"btm_feature_dev_squad_backend":  {PresetID: "backend-developer", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
			"btm_feature_dev_squad_reviewer": {PresetID: "code-reviewer", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
		},
		"code-review-board": {
			"btm_code_review_correctness": {PresetID: "code-reviewer", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "bind_existing"},
			"btm_code_review_risk":        {PresetID: "code-reviewer", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "bind_existing"},
			"btm_code_review_tests":       {PresetID: "code-reviewer", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "bind_existing"},
		},
		"bug-hunt-regression-fix": {
			"btm_bug_hunt_reproducer": {PresetID: "debugger", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
			"btm_bug_hunt_root_cause": {PresetID: "debugger", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
			"btm_bug_hunt_fixer":      {PresetID: "general-purpose", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
			"btm_bug_hunt_verifier":   {PresetID: "qa-engineer", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
		},
		"decision-memo-crew": {
			"btm_decision_researcher": {PresetID: "general-purpose", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
			"btm_decision_skeptic":    {PresetID: "general-purpose", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
			"btm_decision_writer":     {PresetID: "general-purpose", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
		},
		"incident-triage-room": {
			"btm_incident_logs":       {PresetID: "debugger", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
			"btm_incident_infra":      {PresetID: "devops-engineer", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
			"btm_incident_mitigation": {PresetID: "devops-engineer", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
			"btm_incident_status":     {PresetID: "general-purpose", PresetVersion: "v1", RoleRequired: false, RoleRealizationPolicy: "optional_existing"},
		},
		"knowledge-builder": {
			"btm_knowledge_source_reader":    {PresetID: "general-purpose", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
			"btm_knowledge_structure_editor": {PresetID: "general-purpose", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
			"btm_knowledge_example_writer":   {PresetID: "general-purpose", PresetVersion: "v1", RoleRequired: true, RoleRealizationPolicy: "create_agent"},
		},
	}

	for _, template := range templates {
		wantMembers, ok := want[template.Slug]
		if !ok {
			t.Fatalf("unexpected template %q", template.Slug)
		}
		if len(template.Members) != len(wantMembers) {
			t.Fatalf("template %q member count = %d, want %d", template.Slug, len(template.Members), len(wantMembers))
		}
		for _, member := range template.Members {
			wantMember, ok := wantMembers[member.ID]
			if !ok {
				t.Fatalf("template %q has unexpected member %q", template.Slug, member.ID)
			}
			if member.PresetID != wantMember.PresetID {
				t.Errorf("%s/%s PresetID = %q, want %q", template.Slug, member.ID, member.PresetID, wantMember.PresetID)
			}
			if member.PresetVersion != wantMember.PresetVersion {
				t.Errorf("%s/%s PresetVersion = %q, want %q", template.Slug, member.ID, member.PresetVersion, wantMember.PresetVersion)
			}
			if member.RoleRequired != wantMember.RoleRequired {
				t.Errorf("%s/%s RoleRequired = %v, want %v", template.Slug, member.ID, member.RoleRequired, wantMember.RoleRequired)
			}
			if member.RoleRealizationPolicy != wantMember.RoleRealizationPolicy {
				t.Errorf("%s/%s RoleRealizationPolicy = %q, want %q", template.Slug, member.ID, member.RoleRealizationPolicy, wantMember.RoleRealizationPolicy)
			}
		}
	}
}

func TestParseTeamTemplateMetaValidatesRoleMetadata(t *testing.T) {
	base := `id: builtin_test
slug: test-template
visibility: workspace
scope: workspace
members:
  - id: btm_test
    file: test
    actor_kind: agent
    wake_on_team_mention: true
    sort_order: 10
    preset_id: general-purpose
    preset_version: v1
    role_required: true
    role_realization_policy: create_agent
`
	if _, err := parseTeamTemplateMeta("test-template", []byte(base)); err != nil {
		t.Fatalf("valid metadata: %v", err)
	}

	cases := []struct {
		name      string
		old       string
		repl      string
		wantError string
	}{
		{
			name:      "missing preset_id",
			old:       "    preset_id: general-purpose\n",
			repl:      "",
			wantError: "preset_id is required",
		},
		{
			name:      "missing preset_version",
			old:       "    preset_version: v1\n",
			repl:      "",
			wantError: "preset_version is required",
		},
		{
			name:      "missing role_required",
			old:       "    role_required: true\n",
			repl:      "",
			wantError: "role_required is required",
		},
		{
			name:      "invalid policy",
			old:       "    role_realization_policy: create_agent\n",
			repl:      "    role_realization_policy: sometimes\n",
			wantError: "role_realization_policy must be create_agent, bind_existing, or optional_existing",
		},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			raw := strings.Replace(base, tc.old, tc.repl, 1)
			_, err := parseTeamTemplateMeta("test-template", []byte(raw))
			if err == nil {
				t.Fatalf("expected error")
			}
			if !strings.Contains(err.Error(), tc.wantError) {
				t.Fatalf("error = %q, want containing %q", err.Error(), tc.wantError)
			}
		})
	}
}

func TestLoadTeamTemplates_Localization(t *testing.T) {
	locales := []string{LocaleEnglish, LocaleSimplifiedChinese, LocaleJapanese, "zh-CN", "ja-JP"}
	for _, locale := range locales {
		templates, err := LoadTeamTemplates(locale)
		if err != nil {
			t.Fatalf("LoadTeamTemplates(%q): %v", locale, err)
		}
		for _, template := range templates {
			if template.Name == "" || template.Name == template.Slug {
				t.Errorf("locale=%q template=%q missing localized Name (got %q)", locale, template.Slug, template.Name)
			}
			for _, member := range template.Members {
				if strings.TrimSpace(member.RoleOverlayPrompt) == "" {
					t.Errorf("locale=%q template=%q member=%q empty role_overlay_prompt", locale, template.Slug, member.ID)
				}
			}
		}
	}
}

func TestTeamTemplateByID(t *testing.T) {
	template, err := TeamTemplateByID("builtin_feature_dev_squad", LocaleSimplifiedChinese)
	if err != nil {
		t.Fatalf("TeamTemplateByID: %v", err)
	}
	if template.Slug != "feature-dev-squad" {
		t.Errorf("slug = %q, want feature-dev-squad", template.Slug)
	}
	if !strings.Contains(template.Description, "负责人") {
		t.Errorf("zh-CN description did not localize; got %q", template.Description)
	}
	if template.Name != "功能开发小队" {
		t.Errorf("zh-CN Name = %q, want 功能开发小队", template.Name)
	}
}

func TestTeamTemplateSlugs(t *testing.T) {
	slugs, err := TeamTemplateSlugs()
	if err != nil {
		t.Fatalf("TeamTemplateSlugs: %v", err)
	}
	if len(slugs) != 6 {
		t.Fatalf("expected 6 slugs, got %d", len(slugs))
	}
}

func TestSplitMarkdownFrontMatter(t *testing.T) {
	front, body, err := splitMarkdownFrontMatter([]byte("---\nrole_label: Hi\n---\nbody text\n"))
	if err != nil {
		t.Fatalf("splitMarkdownFrontMatter: %v", err)
	}
	if string(front) != "role_label: Hi" {
		t.Errorf("front = %q", front)
	}
	if body != "body text" {
		t.Errorf("body = %q", body)
	}

	_, _, err = splitMarkdownFrontMatter([]byte("---\nrole_label: Hi\nno end"))
	if err == nil {
		t.Fatalf("expected error for unterminated front matter")
	}

	front, body, err = splitMarkdownFrontMatter([]byte("just text"))
	if err != nil {
		t.Fatalf("plain body: %v", err)
	}
	if front != nil {
		t.Errorf("front should be nil, got %q", front)
	}
	if body != "just text" {
		t.Errorf("body = %q", body)
	}
}
