package git_commands

import (
	"testing"

	"github.com/jesseduffield/lazygit/pkg/commands/hosting_service"
	"github.com/jesseduffield/lazygit/pkg/commands/models"
	"github.com/stretchr/testify/assert"
)

func TestGetRepoInfoFromURL(t *testing.T) {
	cases := []struct {
		name     string
		url      string
		expected hosting_service.RepoInformation
	}{
		{
			name: "SSH URL",
			url:  "git@github.com:jesseduffield/lazygit.git",
			expected: hosting_service.RepoInformation{
				Owner:      "jesseduffield",
				Repository: "lazygit",
			},
		},
		{
			name: "HTTPS URL",
			url:  "https://github.com/jesseduffield/lazygit.git",
			expected: hosting_service.RepoInformation{
				Owner:      "jesseduffield",
				Repository: "lazygit",
			},
		},
		{
			name: "HTTPS URL without .git",
			url:  "https://github.com/jesseduffield/lazygit",
			expected: hosting_service.RepoInformation{
				Owner:      "jesseduffield",
				Repository: "lazygit",
			},
		},
		{
			name: "SSH URL with org nesting",
			url:  "git@github.com:my-org/sub-group/lazygit.git",
			expected: hosting_service.RepoInformation{
				Owner:      "my-org/sub-group",
				Repository: "lazygit",
			},
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			result, err := hosting_service.GetRepoInfoFromURL(c.url)
			assert.NoError(t, err)
			assert.Equal(t, c.expected, result)
		})
	}
}

func TestGraphQLEndpoint(t *testing.T) {
	cases := []struct {
		host     string
		expected string
	}{
		{"github.com", "https://api.github.com/graphql"},
		{"www.github.com", "https://api.github.com/graphql"},
		{"GITHUB.com", "https://api.github.com/graphql"},
		{"ghe.example.com", "https://ghe.example.com/api/graphql"},
		{"ghe.example.com:8443", "https://ghe.example.com:8443/api/graphql"},
	}

	for _, c := range cases {
		t.Run(c.host, func(t *testing.T) {
			assert.Equal(t, c.expected, graphQLEndpoint(c.host))
		})
	}
}

func TestGenerateGithubPullRequestMap(t *testing.T) {
	cases := []struct {
		name     string
		prs      []*models.GithubPullRequest
		branches []*models.Branch
		remotes  []*models.Remote
		expected map[string]*models.GithubPullRequest
	}{
		{
			name:     "empty inputs",
			prs:      []*models.GithubPullRequest{},
			branches: []*models.Branch{},
			remotes:  []*models.Remote{},
			expected: map[string]*models.GithubPullRequest{},
		},
		{
			name: "matches PR to branch tracking origin",
			prs: []*models.GithubPullRequest{
				{
					HeadRefName:         "feature-branch",
					Number:              42,
					Title:               "Add feature",
					State:               "OPEN",
					Url:                 "https://github.com/jesseduffield/lazygit/pull/42",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"},
				},
			},
			branches: []*models.Branch{
				{
					Name:           "feature-branch",
					UpstreamRemote: "origin",
					UpstreamBranch: "feature-branch",
				},
			},
			remotes: []*models.Remote{
				{
					Name: "origin",
					Urls: []string{"git@github.com:jesseduffield/lazygit.git"},
				},
			},
			expected: map[string]*models.GithubPullRequest{
				"feature-branch": {
					HeadRefName:         "feature-branch",
					Number:              42,
					Title:               "Add feature",
					State:               "OPEN",
					Url:                 "https://github.com/jesseduffield/lazygit/pull/42",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"},
				},
			},
		},
		{
			name: "does not match branch without upstream",
			prs: []*models.GithubPullRequest{
				{
					HeadRefName:         "feature-branch",
					Number:              42,
					Title:               "Add feature",
					State:               "OPEN",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"},
				},
			},
			branches: []*models.Branch{
				{
					Name: "feature-branch",
					// no upstream set
				},
			},
			remotes: []*models.Remote{
				{
					Name: "origin",
					Urls: []string{"git@github.com:jesseduffield/lazygit.git"},
				},
			},
			expected: map[string]*models.GithubPullRequest{},
		},
		{
			name: "matches fork PR to branch tracking fork remote",
			prs: []*models.GithubPullRequest{
				{
					HeadRefName:         "fix-bug",
					Number:              99,
					Title:               "Fix bug",
					State:               "OPEN",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "contributor"},
				},
			},
			branches: []*models.Branch{
				{
					Name:           "fix-bug",
					UpstreamRemote: "contributor",
					UpstreamBranch: "fix-bug",
				},
			},
			remotes: []*models.Remote{
				{
					Name: "origin",
					Urls: []string{"git@github.com:jesseduffield/lazygit.git"},
				},
				{
					Name: "contributor",
					Urls: []string{"git@github.com:contributor/lazygit.git"},
				},
			},
			expected: map[string]*models.GithubPullRequest{
				"fix-bug": {
					HeadRefName:         "fix-bug",
					Number:              99,
					Title:               "Fix bug",
					State:               "OPEN",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "contributor"},
				},
			},
		},
		{
			name: "does not match when owner differs",
			prs: []*models.GithubPullRequest{
				{
					HeadRefName:         "feature-branch",
					Number:              42,
					Title:               "Add feature",
					State:               "OPEN",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "someone-else"},
				},
			},
			branches: []*models.Branch{
				{
					Name:           "feature-branch",
					UpstreamRemote: "origin",
					UpstreamBranch: "feature-branch",
				},
			},
			remotes: []*models.Remote{
				{
					Name: "origin",
					Urls: []string{"git@github.com:jesseduffield/lazygit.git"},
				},
			},
			expected: map[string]*models.GithubPullRequest{},
		},
		{
			name: "matches when UpstreamRemote is a full URL",
			prs: []*models.GithubPullRequest{
				{
					HeadRefName:         "my-branch",
					Number:              55,
					Title:               "Full URL upstream",
					State:               "OPEN",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "contributor"},
				},
			},
			branches: []*models.Branch{
				{
					Name:           "my-branch",
					UpstreamRemote: "git@github.com:contributor/lazygit.git",
					UpstreamBranch: "my-branch",
				},
			},
			remotes: []*models.Remote{
				{
					Name: "origin",
					Urls: []string{"git@github.com:jesseduffield/lazygit.git"},
				},
			},
			expected: map[string]*models.GithubPullRequest{
				"my-branch": {
					HeadRefName:         "my-branch",
					Number:              55,
					Title:               "Full URL upstream",
					State:               "OPEN",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "contributor"},
				},
			},
		},
		{
			name: "uses first PR when branch name is reused (API returns newest first)",
			prs: []*models.GithubPullRequest{
				// API returns newest first (CREATED_AT DESC)
				{
					HeadRefName:         "update-sponsors",
					Number:              50,
					Title:               "Newest PR",
					State:               "CLOSED",
					Url:                 "https://github.com/jesseduffield/lazygit/pull/50",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"},
				},
				{
					HeadRefName:         "update-sponsors",
					Number:              30,
					Title:               "Middle PR",
					State:               "OPEN",
					Url:                 "https://github.com/jesseduffield/lazygit/pull/30",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"},
				},
				{
					HeadRefName:         "update-sponsors",
					Number:              10,
					Title:               "Oldest PR",
					State:               "CLOSED",
					Url:                 "https://github.com/jesseduffield/lazygit/pull/10",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"},
				},
			},
			branches: []*models.Branch{
				{
					Name:           "update-sponsors",
					UpstreamRemote: "origin",
					UpstreamBranch: "update-sponsors",
				},
			},
			remotes: []*models.Remote{
				{
					Name: "origin",
					Urls: []string{"git@github.com:jesseduffield/lazygit.git"},
				},
			},
			expected: map[string]*models.GithubPullRequest{
				"update-sponsors": {
					HeadRefName:         "update-sponsors",
					Number:              50,
					Title:               "Newest PR",
					State:               "CLOSED",
					Url:                 "https://github.com/jesseduffield/lazygit/pull/50",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"},
				},
			},
		},
		{
			name: "matches with HTTPS remote URL",
			prs: []*models.GithubPullRequest{
				{
					HeadRefName:         "my-pr",
					Number:              10,
					Title:               "My PR",
					State:               "MERGED",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"},
				},
			},
			branches: []*models.Branch{
				{
					Name:           "my-pr",
					UpstreamRemote: "origin",
					UpstreamBranch: "my-pr",
				},
			},
			remotes: []*models.Remote{
				{
					Name: "origin",
					Urls: []string{"https://github.com/jesseduffield/lazygit.git"},
				},
			},
			expected: map[string]*models.GithubPullRequest{
				"my-pr": {
					HeadRefName:         "my-pr",
					Number:              10,
					Title:               "My PR",
					State:               "MERGED",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"},
				},
			},
		},
		{
			name: "matches when owner casing differs",
			prs: []*models.GithubPullRequest{
				{
					HeadRefName:         "fix-case-insensitive",
					Number:              42,
					Title:               "Fix case insensitive",
					State:               "OPEN",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "Jesseduffield"}, // Uppercase J
				},
			},
			branches: []*models.Branch{
				{
					Name:           "fix-case-insensitive",
					UpstreamRemote: "origin",
					UpstreamBranch: "fix-case-insensitive",
				},
			},
			remotes: []*models.Remote{
				{
					Name: "origin",
					Urls: []string{"git@github.com:jesseduffield/lazygit.git"}, // Lowercase j
				},
			},
			expected: map[string]*models.GithubPullRequest{
				"fix-case-insensitive": {
					HeadRefName:         "fix-case-insensitive",
					Number:              42,
					Title:               "Fix case insensitive",
					State:               "OPEN",
					HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "Jesseduffield"},
				},
			},
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			result := GenerateGithubPullRequestMap(c.prs, c.branches, c.remotes)
			assert.Equal(t, c.expected, result)
		})
	}
}
