package android

import (
	"path"
	"path/filepath"

	"android/soong/android/team_proto"

	"google.golang.org/protobuf/proto"
)

const ownershipDirectory = "ownership"
const allTeamsFile = "all_teams.pb"

func AllTeamsFactory() Singleton {
	return &allTeamsSingleton{}
}

func init() {
	registerAllTeamBuildComponents(InitRegistrationContext)
}

func registerAllTeamBuildComponents(ctx RegistrationContext) {
	ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
}

// For each module, list the team or the bpFile the module is defined in.
type moduleTeamAndTestInfo struct {
	// Name field from bp file for the team
	teamName string
	// Blueprint file the module is located in.
	bpFile string
	// Is this module only used by tests.
	testOnly bool
	// Is this a directly testable target by running the module directly
	// or via tradefed.
	topLevelTestTarget bool
	// String name indicating the module, like `java_library` for reporting.
	kind string
}

type allTeamsSingleton struct {
	// Path where the collected metadata is stored after successful validation.
	outputPath OutputPath

	// Map of all package modules we visit during GenerateBuildActions
	packages map[string]packageProperties
	// Map of all team modules we visit during GenerateBuildActions
	teams map[string]teamProperties
	// Keeps track of team information or bp file for each module we visit.
	teams_for_mods map[string]moduleTeamAndTestInfo
}

// See if there is a package module for the given bpFilePath with a team defined, if so return the team.
// If not ascend up to the parent directory and do the same.
func (t *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamProperties, bool) {
	// return the Default_team listed in the package if is there.
	if p, ok := t.packages[bpFilePath]; ok {
		if defaultTeam := p.Default_team; defaultTeam != nil {
			return t.teams[*defaultTeam], true
		}
	}
	// Strip a directory and go up.
	// Does android/paths.go basePath,SourcePath help?
	current, base := filepath.Split(bpFilePath)
	current = filepath.Clean(current) // removes trailing slash, convert "" -> "."
	parent, _ := filepath.Split(current)
	if current == "." {
		return teamProperties{}, false
	}
	return t.lookupDefaultTeam(filepath.Join(parent, base))
}

// Visit all modules and collect all teams and use WriteFileRuleVerbatim
// to write it out.
func (t *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) {
	t.packages = make(map[string]packageProperties)
	t.teams = make(map[string]teamProperties)
	t.teams_for_mods = make(map[string]moduleTeamAndTestInfo)

	ctx.VisitAllModules(func(module Module) {
		bpFile := ctx.BlueprintFile(module)

		// Package Modules and Team Modules are stored in a map so we can look them up by name for
		// modules without a team.
		if pack, ok := module.(*packageModule); ok {
			// Packages don't have names, use the blueprint file as the key. we can't get qualifiedModuleId in t context.
			pkgKey := bpFile
			t.packages[pkgKey] = pack.properties
			return
		}
		if team, ok := module.(*teamModule); ok {
			t.teams[team.Name()] = team.properties
			return
		}

		testModInfo := TestModuleInformation{}
		if tmi, ok := OtherModuleProvider(ctx, module, TestOnlyProviderKey); ok {
			testModInfo = tmi
		}

		// Some modules, like java_test_host don't set the provider when the module isn't enabled:
		//                                                test_only, top_level
		//     AVFHostTestCases{os:linux_glibc,arch:common} {true true}
		//     AVFHostTestCases{os:windows,arch:common} {false false}
		// Generally variant information of true override false or unset.
		if testModInfo.TestOnly == false {
			if prevValue, exists := t.teams_for_mods[module.Name()]; exists {
				if prevValue.testOnly == true {
					return
				}
			}
		}
		entry := moduleTeamAndTestInfo{
			bpFile:             bpFile,
			testOnly:           testModInfo.TestOnly,
			topLevelTestTarget: testModInfo.TopLevelTarget,
			kind:               ctx.ModuleType(module),
			teamName:           module.base().Team(),
		}
		t.teams_for_mods[module.Name()] = entry

	})

	// Visit all modules again and lookup the team name in the package or parent package if the team
	// isn't assignged at the module level.
	allTeams := t.lookupTeamForAllModules()

	t.outputPath = PathForOutput(ctx, ownershipDirectory, allTeamsFile)
	data, err := proto.Marshal(allTeams)
	if err != nil {
		ctx.Errorf("Unable to marshal team data. %s", err)
	}

	WriteFileRuleVerbatim(ctx, t.outputPath, string(data))
	ctx.Phony("all_teams", t.outputPath)
}

func (t *allTeamsSingleton) MakeVars(ctx MakeVarsContext) {
	ctx.DistForGoal("all_teams", t.outputPath)
}

// Visit every (non-package, non-team) module and write out a proto containing
// either the declared team data for that module or the package default team data for that module.
func (t *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams {
	teamsProto := make([]*team_proto.Team, len(t.teams_for_mods))
	for i, moduleName := range SortedKeys(t.teams_for_mods) {
		m, _ := t.teams_for_mods[moduleName]
		teamName := m.teamName
		var teamProperties teamProperties
		found := false
		if teamName != "" {
			teamProperties, found = t.teams[teamName]
		} else {
			teamProperties, found = t.lookupDefaultTeam(m.bpFile)
		}
		// Deal with one blueprint file including another by looking up the default
		// in the main Android.bp rather than one listed with "build = [My.bp]"
		if !found {
			teamProperties, found = t.lookupDefaultTeam(path.Join(path.Dir(m.bpFile), "Android.bp"))
		}

		trendy_team_id := ""
		if found {
			trendy_team_id = *teamProperties.Trendy_team_id
		}

		teamData := new(team_proto.Team)
		*teamData = team_proto.Team{
			TargetName:     proto.String(moduleName),
			Path:           proto.String(m.bpFile),
			TestOnly:       proto.Bool(m.testOnly),
			TopLevelTarget: proto.Bool(m.topLevelTestTarget),
			Kind:           proto.String(m.kind),
		}
		if trendy_team_id != "" {
			teamData.TrendyTeamId = proto.String(trendy_team_id)
		} else {
			// Clients rely on the TrendyTeamId optional field not being set.
		}
		teamsProto[i] = teamData
	}
	return &team_proto.AllTeams{Teams: teamsProto}
}
