package main

import (
	"encoding/json"

	"src.opensuse.org/autogits/common"
)

//go:generate mockgen -source=maintainership.go -destination=mock/maintainership.go -typed

type MaintainershipData interface {
	ListProjectMaintainers() []string
	ListPackageMaintainers(pkg string) []string
}

const ProjectKey = ""
const ProjectFileKey = "_project"

type MaintainershipMap struct {
	data         map[string][]string
	is_dir       bool
	fetchPackage func(string) ([]byte, error)
}

func parseMaintainershipData(data []byte) (*MaintainershipMap, error) {
	maintainers := &MaintainershipMap{
		data: make(map[string][]string),
	}
	if err := json.Unmarshal(data, &maintainers.data); err != nil {
		return nil, err
	}

	return maintainers, nil
}

func FetchProjectMaintainershipData(gitea common.GiteaMaintainershipInterface, org, prjGit, branch string) (*MaintainershipMap, error) {
	data, err := gitea.FetchMaintainershipDirFile(org, prjGit, branch, ProjectFileKey)
	dir := true
	if err != nil || data == nil {
		dir = false
		data, err = gitea.FetchMaintainershipFile(org, prjGit, branch)
		if err != nil || data == nil {
			return nil, err
		}
	}

	m, err := parseMaintainershipData(data)
	if m != nil {
		m.is_dir = dir
		m.fetchPackage = func(pkg string) ([]byte, error) {
			return gitea.FetchMaintainershipDirFile(org, prjGit, branch, pkg)
		}
	}
	return m, err
}

func (data *MaintainershipMap) ListProjectMaintainers() []string {
	if data == nil {
		return nil
	}

	m, found := data.data[ProjectKey]
	if !found {
		return nil
	}

	return m
}

func parsePkgDirData(pkg string, data []byte) []string {
	m := make(map[string][]string)
	if err := json.Unmarshal(data, &m); err != nil {
		return nil
	}

	pkgMaintainers, found := m[pkg]
	if !found {
		return nil
	}
	return pkgMaintainers
}

func (data *MaintainershipMap) ListPackageMaintainers(pkg string) []string {
	if data == nil {
		return nil
	}

	pkgMaintainers, found := data.data[pkg]
	if !found && data.is_dir {
		pkgData, err := data.fetchPackage(pkg)
		if err == nil {
			pkgMaintainers = parsePkgDirData(pkg, pkgData)
			if len(pkgMaintainers) > 0 {
				data.data[pkg] = pkgMaintainers
			}
		}
	}
	prjMaintainers := data.ListProjectMaintainers()

prjMaintainer:
	for _, prjm := range prjMaintainers {
		for i := range pkgMaintainers {
			if pkgMaintainers[i] == prjm {
				continue prjMaintainer
			}
		}
		pkgMaintainers = append(pkgMaintainers, prjm)
	}

	return pkgMaintainers
}
