package actions

import (
	"fmt"
	"net/url"
	"strings"
)

var ErrInvalidGitHubConfigURL = fmt.Errorf("invalid config URL, should point to an enterprise, org, or repository")

type GitHubScope int

const (
	GitHubScopeUnknown GitHubScope = iota
	GitHubScopeEnterprise
	GitHubScopeOrganization
	GitHubScopeRepository
)

type GitHubConfig struct {
	ConfigURL *url.URL
	Scope     GitHubScope

	Enterprise   string
	Organization string
	Repository   string

	IsHosted bool
}

func ParseGitHubConfigFromURL(in string) (*GitHubConfig, error) {
	u, err := url.Parse(strings.Trim(in, "/"))
	if err != nil {
		return nil, err
	}

	isHosted := u.Host == "github.com" ||
		u.Host == "www.github.com" ||
		u.Host == "github.localhost"

	configURL := &GitHubConfig{
		ConfigURL: u,
		IsHosted:  isHosted,
	}

	invalidURLError := fmt.Errorf("%q: %w", u.String(), ErrInvalidGitHubConfigURL)

	pathParts := strings.Split(strings.Trim(u.Path, "/"), "/")

	switch len(pathParts) {
	case 1: // Organization
		if pathParts[0] == "" {
			return nil, invalidURLError
		}

		configURL.Scope = GitHubScopeOrganization
		configURL.Organization = pathParts[0]

	case 2: // Repository or enterprise
		if strings.ToLower(pathParts[0]) == "enterprises" {
			configURL.Scope = GitHubScopeEnterprise
			configURL.Enterprise = pathParts[1]
			break
		}

		configURL.Scope = GitHubScopeRepository
		configURL.Organization = pathParts[0]
		configURL.Repository = pathParts[1]
	default:
		return nil, invalidURLError
	}

	return configURL, nil
}

func (c *GitHubConfig) GitHubAPIURL(path string) *url.URL {
	result := &url.URL{
		Scheme: c.ConfigURL.Scheme,
	}

	switch c.ConfigURL.Host {
	// Hosted
	case "github.com", "github.localhost":
		result.Host = fmt.Sprintf("api.%s", c.ConfigURL.Host)
	// re-routing www.github.com to api.github.com
	case "www.github.com":
		result.Host = "api.github.com"

	// Enterprise
	default:
		result.Host = c.ConfigURL.Host
		result.Path = "/api/v3"
	}

	result.Path += path

	return result
}
