// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package github

import (
	"context"
	"errors"
	"fmt"
	"net/url"

	"github.com/google/go-github/github"
	"github.com/hashicorp/vault/sdk/framework"
	"github.com/hashicorp/vault/sdk/helper/cidrutil"
	"github.com/hashicorp/vault/sdk/helper/policyutil"
	"github.com/hashicorp/vault/sdk/logical"
)

func pathLogin(b *backend) *framework.Path {
	return &framework.Path{
		Pattern: "login",

		DisplayAttrs: &framework.DisplayAttributes{
			OperationPrefix: operationPrefixGithub,
			OperationVerb:   "login",
		},

		Fields: map[string]*framework.FieldSchema{
			"token": {
				Type:        framework.TypeString,
				Description: "GitHub personal API token",
			},
		},

		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.UpdateOperation:         b.pathLogin,
			logical.AliasLookaheadOperation: b.pathLoginAliasLookahead,
		},
	}
}

func (b *backend) pathLoginAliasLookahead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
	token := data.Get("token").(string)

	verifyResp, err := b.verifyCredentials(ctx, req, token)
	if err != nil {
		return nil, err
	}

	return &logical.Response{
		Warnings: verifyResp.Warnings,
		Auth: &logical.Auth{
			Alias: &logical.Alias{
				Name: *verifyResp.User.Login,
			},
		},
	}, nil
}

func (b *backend) pathLogin(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
	token := data.Get("token").(string)

	verifyResp, err := b.verifyCredentials(ctx, req, token)
	if err != nil {
		return nil, err
	}

	auth := &logical.Auth{
		InternalData: map[string]interface{}{
			"token": token,
		},
		Metadata: map[string]string{
			"username": *verifyResp.User.Login,
			"org":      *verifyResp.Org.Login,
		},
		DisplayName: *verifyResp.User.Login,
		Alias: &logical.Alias{
			Name: *verifyResp.User.Login,
		},
	}
	verifyResp.Config.PopulateTokenAuth(auth)

	// Add in configured policies from user/group mapping
	if len(verifyResp.Policies) > 0 {
		auth.Policies = append(auth.Policies, verifyResp.Policies...)
	}

	resp := &logical.Response{
		Warnings: verifyResp.Warnings,
		Auth:     auth,
	}

	for _, teamName := range verifyResp.TeamNames {
		if teamName == "" {
			continue
		}
		resp.Auth.GroupAliases = append(resp.Auth.GroupAliases, &logical.Alias{
			Name: teamName,
		})
	}

	return resp, nil
}

func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	if req.Auth == nil {
		return nil, fmt.Errorf("request auth was nil")
	}

	tokenRaw, ok := req.Auth.InternalData["token"]
	if !ok {
		return nil, fmt.Errorf("token created in previous version of Vault cannot be validated properly at renewal time")
	}
	token := tokenRaw.(string)

	verifyResp, err := b.verifyCredentials(ctx, req, token)
	if err != nil {
		return nil, err
	}

	if !policyutil.EquivalentPolicies(verifyResp.Policies, req.Auth.TokenPolicies) {
		return nil, fmt.Errorf("policies do not match")
	}

	resp := &logical.Response{Auth: req.Auth}
	resp.Auth.Period = verifyResp.Config.TokenPeriod
	resp.Auth.TTL = verifyResp.Config.TokenTTL
	resp.Auth.MaxTTL = verifyResp.Config.TokenMaxTTL
	resp.Warnings = verifyResp.Warnings

	// Remove old aliases
	resp.Auth.GroupAliases = nil

	for _, teamName := range verifyResp.TeamNames {
		resp.Auth.GroupAliases = append(resp.Auth.GroupAliases, &logical.Alias{
			Name: teamName,
		})
	}

	return resp, nil
}

func (b *backend) verifyCredentials(ctx context.Context, req *logical.Request, token string) (*verifyCredentialsResp, error) {
	var warnings []string
	config, err := b.Config(ctx, req.Storage)
	if err != nil {
		return nil, err
	}
	if config == nil {
		return nil, errors.New("configuration has not been set")
	}

	// Check for a CIDR match.
	if len(config.TokenBoundCIDRs) > 0 {
		if req.Connection == nil {
			b.Logger().Error("token bound CIDRs found but no connection information available for validation")
			return nil, logical.ErrPermissionDenied
		}
		if !cidrutil.RemoteAddrIsOk(req.Connection.RemoteAddr, config.TokenBoundCIDRs) {
			return nil, logical.ErrPermissionDenied
		}
	}

	client, err := b.Client(token)
	if err != nil {
		return nil, err
	}

	if config.BaseURL != "" {
		parsedURL, err := url.Parse(config.BaseURL)
		if err != nil {
			return nil, fmt.Errorf("successfully parsed base_url when set but failing to parse now: %w", err)
		}
		client.BaseURL = parsedURL
	}

	if config.OrganizationID == 0 {
		// Previously we did not verify using the Org ID. So if the Org ID is
		// not set, we will trust-on-first-use and set it now.
		err = config.setOrganizationID(ctx, client)
		if err != nil {
			b.Logger().Error("failed to set the organization_id on login", "error", err)
			return nil, err
		}
		entry, err := logical.StorageEntryJSON("config", config)
		if err != nil {
			return nil, err
		}

		if err := req.Storage.Put(ctx, entry); err != nil {
			return nil, err
		}

		b.Logger().Info("set ID on a trust-on-first-use basis", "organization_id", config.OrganizationID)
	}

	// Get the user
	user, _, err := client.Users.Get(ctx, "")
	if err != nil {
		return nil, err
	}

	// Verify that the user is part of the organization
	var org *github.Organization

	orgOpt := &github.ListOptions{
		PerPage: 100,
	}

	var allOrgs []*github.Organization
	for {
		orgs, resp, err := client.Organizations.List(ctx, "", orgOpt)
		if err != nil {
			return nil, err
		}
		allOrgs = append(allOrgs, orgs...)
		if resp.NextPage == 0 {
			break
		}
		orgOpt.Page = resp.NextPage
	}

	orgLoginName := ""
	for _, o := range allOrgs {
		if o.GetID() == config.OrganizationID {
			org = o
			orgLoginName = *o.Login
			break
		}
	}
	if org == nil {
		return nil, errors.New("user is not part of required org")
	}

	if orgLoginName != config.Organization {
		warningMsg := fmt.Sprintf(
			"the organization name has changed to %q. It is recommended to verify and update the organization name in the config: %s=%d",
			orgLoginName,
			"organization_id",
			config.OrganizationID,
		)
		b.Logger().Warn(warningMsg)
		warnings = append(warnings, warningMsg)
	}

	// Get the teams that this user is part of to determine the policies
	var teamNames []string

	teamOpt := &github.ListOptions{
		PerPage: 100,
	}

	var allTeams []*github.Team
	for {
		teams, resp, err := client.Teams.ListUserTeams(ctx, teamOpt)
		if err != nil {
			return nil, err
		}
		allTeams = append(allTeams, teams...)
		if resp.NextPage == 0 {
			break
		}
		teamOpt.Page = resp.NextPage
	}

	for _, t := range allTeams {
		// We only care about teams that are part of the organization we use
		if *t.Organization.ID != *org.ID {
			continue
		}

		// Append the names so we can get the policies
		teamNames = append(teamNames, *t.Name)
		if *t.Name != *t.Slug {
			teamNames = append(teamNames, *t.Slug)
		}
	}

	groupPoliciesList, err := b.TeamMap.Policies(ctx, req.Storage, teamNames...)
	if err != nil {
		return nil, err
	}

	userPoliciesList, err := b.UserMap.Policies(ctx, req.Storage, []string{*user.Login}...)
	if err != nil {
		return nil, err
	}

	verifyResp := &verifyCredentialsResp{
		User:      user,
		Org:       org,
		Policies:  append(groupPoliciesList, userPoliciesList...),
		TeamNames: teamNames,
		Config:    config,
		Warnings:  warnings,
	}

	return verifyResp, nil
}

type verifyCredentialsResp struct {
	User      *github.User
	Org       *github.Organization
	Policies  []string
	TeamNames []string

	// Warnings to send back to the caller
	Warnings []string

	// This is just a cache to send back to the caller
	Config *config
}
