package api

import (
	"github.com/cli/cli/v2/internal/ghrepo"
	"github.com/shurcooL/githubv4"
)

// OrganizationProjects fetches all open projects for an organization.
func OrganizationProjects(client *Client, repo ghrepo.Interface) ([]RepoProject, error) {
	type responseData struct {
		Organization struct {
			Projects struct {
				Nodes    []RepoProject
				PageInfo struct {
					HasNextPage bool
					EndCursor   string
				}
			} `graphql:"projects(states: [OPEN], first: 100, orderBy: {field: NAME, direction: ASC}, after: $endCursor)"`
		} `graphql:"organization(login: $owner)"`
	}

	variables := map[string]interface{}{
		"owner":     githubv4.String(repo.RepoOwner()),
		"endCursor": (*githubv4.String)(nil),
	}

	var projects []RepoProject
	for {
		var query responseData
		err := client.Query(repo.RepoHost(), "OrganizationProjectList", &query, variables)
		if err != nil {
			return nil, err
		}

		projects = append(projects, query.Organization.Projects.Nodes...)
		if !query.Organization.Projects.PageInfo.HasNextPage {
			break
		}
		variables["endCursor"] = githubv4.String(query.Organization.Projects.PageInfo.EndCursor)
	}

	return projects, nil
}

// OrganizationProjectsV2 fetches all open projectsV2 for an organization.
func OrganizationProjectsV2(client *Client, repo ghrepo.Interface) ([]RepoProjectV2, error) {
	type responseData struct {
		Organization struct {
			ProjectsV2 struct {
				Nodes    []RepoProjectV2
				PageInfo struct {
					HasNextPage bool
					EndCursor   string
				}
			} `graphql:"projectsV2(first: 100, orderBy: {field: TITLE, direction: ASC}, after: $endCursor, query: $query)"`
		} `graphql:"organization(login: $owner)"`
	}

	variables := map[string]interface{}{
		"owner":     githubv4.String(repo.RepoOwner()),
		"endCursor": (*githubv4.String)(nil),
		"query":     githubv4.String("is:open"),
	}

	var projectsV2 []RepoProjectV2
	for {
		var query responseData
		err := client.Query(repo.RepoHost(), "OrganizationProjectV2List", &query, variables)
		if err != nil {
			return nil, err
		}

		projectsV2 = append(projectsV2, query.Organization.ProjectsV2.Nodes...)

		if !query.Organization.ProjectsV2.PageInfo.HasNextPage {
			break
		}
		variables["endCursor"] = githubv4.String(query.Organization.ProjectsV2.PageInfo.EndCursor)
	}

	return projectsV2, nil
}

type OrgTeam struct {
	ID   string
	Slug string
}

// OrganizationTeams fetches all the teams in an organization
func OrganizationTeams(client *Client, repo ghrepo.Interface) ([]OrgTeam, error) {
	type responseData struct {
		Organization struct {
			Teams struct {
				Nodes    []OrgTeam
				PageInfo struct {
					HasNextPage bool
					EndCursor   string
				}
			} `graphql:"teams(first: 100, orderBy: {field: NAME, direction: ASC}, after: $endCursor)"`
		} `graphql:"organization(login: $owner)"`
	}

	variables := map[string]interface{}{
		"owner":     githubv4.String(repo.RepoOwner()),
		"endCursor": (*githubv4.String)(nil),
	}

	var teams []OrgTeam
	for {
		var query responseData
		err := client.Query(repo.RepoHost(), "OrganizationTeamList", &query, variables)
		if err != nil {
			return nil, err
		}

		teams = append(teams, query.Organization.Teams.Nodes...)
		if !query.Organization.Teams.PageInfo.HasNextPage {
			break
		}
		variables["endCursor"] = githubv4.String(query.Organization.Teams.PageInfo.EndCursor)
	}

	return teams, nil
}
