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

package getter

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"
)

// BitBucketDetector implements Detector to detect BitBucket URLs and turn
// them into URLs that the Git or Hg Getter can understand.
type BitBucketDetector struct{}

func (d *BitBucketDetector) Detect(src, _ string) (string, bool, error) {
	if len(src) == 0 {
		return "", false, nil
	}

	if strings.HasPrefix(src, "bitbucket.org/") {
		return d.detectHTTP(src)
	}

	return "", false, nil
}

func (d *BitBucketDetector) detectHTTP(src string) (string, bool, error) {
	u, err := url.Parse("https://" + src)
	if err != nil {
		return "", true, fmt.Errorf("error parsing BitBucket URL: %s", err)
	}

	// We need to get info on this BitBucket repository to determine whether
	// it is Git or Hg.
	var info struct {
		SCM string `json:"scm"`
	}
	infoUrl := "https://api.bitbucket.org/2.0/repositories" + u.Path
	resp, err := http.Get(infoUrl)
	if err != nil {
		return "", true, fmt.Errorf("error looking up BitBucket URL: %s", err)
	}
	if resp.StatusCode == 403 {
		// A private repo
		return "", true, fmt.Errorf(
			"shorthand BitBucket URL can't be used for private repos, " +
				"please use a full URL")
	}
	dec := json.NewDecoder(resp.Body)
	if err := dec.Decode(&info); err != nil {
		return "", true, fmt.Errorf("error looking up BitBucket URL: %s", err)
	}

	switch info.SCM {
	case "git":
		if !strings.HasSuffix(u.Path, ".git") {
			u.Path += ".git"
		}

		return "git::" + u.String(), true, nil
	case "hg":
		return "hg::" + u.String(), true, nil
	default:
		return "", true, fmt.Errorf("unknown BitBucket SCM type: %s", info.SCM)
	}
}
