package repoinfo

import (
	"fmt"
	"path"
	"slices"

	"github.com/bluesky-social/indigo/atproto/syntax"
	"tangled.org/core/api/tangled"
	"tangled.org/core/appview/models"
	"tangled.org/core/appview/state/userutil"
)

func (r RepoInfo) owner() string {
	if r.OwnerHandle != "" {
		return r.OwnerHandle
	} else {
		return r.OwnerDid
	}
}

func (r RepoInfo) Slug() string {
	if r.Name != "" {
		return r.Name
	}
	return r.Rkey
}

func (r RepoInfo) FullName() string {
	return path.Join(r.owner(), r.Slug())
}

// UrlBase returns the URL prefix used to build intra-repo links.
// In project mode the owner is implicit so only the rkey is needed;
// otherwise it returns the full owner/rkey path.
func (r RepoInfo) UrlBase() string {
	if r.ProjectMode {
		return r.Rkey
	}
	return r.FullName()
}

func (r RepoInfo) RepoIdentifier() string {
	if r.RepoDid != "" {
		return r.RepoDid
	}
	return path.Join(r.OwnerDid, r.Name)
}

func (r RepoInfo) ownerWithoutAt() string {
	if r.OwnerHandle != "" {
		return r.OwnerHandle
	} else {
		return userutil.FlattenDid(r.OwnerDid)
	}
}

func (r RepoInfo) FullNameWithoutAt() string {
	return path.Join(r.ownerWithoutAt(), r.Slug())
}

func (r RepoInfo) GetTabs() [][]string {
	tabs := [][]string{
		{"overview", "/", "square-chart-gantt"},
		{"issues", "/issues", "circle-dot"},
		{"pulls", "/pulls", "git-pull-request"},
		{"pipelines", "/pipelines", "layers-2"},
	}

	if r.Roles.SettingsAllowed() {
		tabs = append(tabs, []string{"settings", "/settings", "cog"})
	}

	return tabs
}

func (r RepoInfo) RepoAt() syntax.ATURI {
	return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", r.OwnerDid, tangled.RepoNSID, r.Rkey))
}

type RepoInfo struct {
	Name        string
	Rkey        string
	OwnerDid    string
	OwnerHandle string
	RepoDid     string
	ProjectMode bool
	Description string
	Website     string
	Topics      []string
	Knot        string
	Spindle     string
	IsStarred   bool
	Stats       models.RepoStats
	Roles       RolesInRepo
	Source      *models.Repo
	Ref         string
	CurrentDir  string
}

// each tab on a repo could have some metadata:
//
// issues -> number of open issues etc.
// settings -> a warning icon to setup branch protection? idk
//
// we gather these bits of info here, because go templates
// are difficult to program in
func (r RepoInfo) TabMetadata() map[string]any {
	meta := make(map[string]any)

	meta["pulls"] = r.Stats.PullCount.Open
	meta["issues"] = r.Stats.IssueCount.Open

	// more stuff?

	return meta
}

type RolesInRepo struct {
	Roles []string
}

func (r RolesInRepo) SettingsAllowed() bool {
	return slices.Contains(r.Roles, "repo:settings")
}

func (r RolesInRepo) CollaboratorInviteAllowed() bool {
	return slices.Contains(r.Roles, "repo:invite")
}

func (r RolesInRepo) RepoDeleteAllowed() bool {
	return slices.Contains(r.Roles, "repo:delete")
}

func (r RolesInRepo) IsOwner() bool {
	return slices.Contains(r.Roles, "repo:owner")
}

func (r RolesInRepo) IsCollaborator() bool {
	return slices.Contains(r.Roles, "repo:collaborator")
}

func (r RolesInRepo) IsPushAllowed() bool {
	return slices.Contains(r.Roles, "repo:push")
}
