// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package organization

import (
	"context"

	"code.gitea.io/gitea/models/db"
	user_model "code.gitea.io/gitea/models/user"
)

const (
	// ProfileRepoName is the name of the special profile repository
	ProfileRepoName = ".profile"
	// ProfileReadmePath is the path to the profile README
	ProfileReadmePath = "README.md"
	// ProfileAssetsPath is the path to profile assets
	ProfileAssetsPath = "assets/"
	// ProfileStylePath is the path to custom CSS
	ProfileStylePath = "style.css"
)

// PublicMember represents a public member of an organization for display
type PublicMember struct {
	*user_model.User
	Role string // "Owner", "Admin", "Member"
}

// GetPublicOrgMembers returns public members of an organization
func GetPublicOrgMembers(ctx context.Context, orgID int64, limit int) ([]*PublicMember, int64, error) {
	// Count total public members
	total, err := db.GetEngine(ctx).
		Where("org_id = ? AND is_public = ?", orgID, true).
		Count(new(OrgUser))
	if err != nil {
		return nil, 0, err
	}

	// Get public org users
	orgUsers := make([]*OrgUser, 0, limit)
	sess := db.GetEngine(ctx).
		Where("org_id = ? AND is_public = ?", orgID, true)
	if limit > 0 {
		sess = sess.Limit(limit)
	}
	if err := sess.Find(&orgUsers); err != nil {
		return nil, 0, err
	}

	if len(orgUsers) == 0 {
		return []*PublicMember{}, total, nil
	}

	// Get user IDs
	userIDs := make([]int64, len(orgUsers))
	for i, ou := range orgUsers {
		userIDs[i] = ou.UID
	}

	// Load users
	users, err := user_model.GetUsersByIDs(ctx, userIDs)
	if err != nil {
		return nil, 0, err
	}

	userMap := make(map[int64]*user_model.User)
	for _, u := range users {
		userMap[u.ID] = u
	}

	// Get owners team to determine roles
	org, err := GetOrgByID(ctx, orgID)
	if err != nil {
		return nil, 0, err
	}

	ownersTeam, err := org.GetOwnerTeam(ctx)
	if err != nil {
		return nil, 0, err
	}

	ownerIDs := make(map[int64]bool)
	if ownersTeam != nil {
		if err := ownersTeam.LoadMembers(ctx); err != nil {
			return nil, 0, err
		}
		for _, m := range ownersTeam.Members {
			ownerIDs[m.ID] = true
		}
	}

	// Build result with roles
	members := make([]*PublicMember, 0, len(orgUsers))
	for _, ou := range orgUsers {
		user := userMap[ou.UID]
		if user == nil {
			continue
		}

		role := "Member"
		if ownerIDs[ou.UID] {
			role = "Owner"
		} else {
			// Check if admin (has admin access to any team)
			isAdmin, _ := IsOrganizationAdmin(ctx, orgID, ou.UID)
			if isAdmin {
				role = "Admin"
			}
		}

		members = append(members, &PublicMember{
			User: user,
			Role: role,
		})
	}

	return members, total, nil
}

// SetMemberPublicVisibility sets the public visibility of a member
func SetMemberPublicVisibility(ctx context.Context, orgID, userID int64, isPublic bool) error {
	_, err := db.GetEngine(ctx).
		Where("org_id = ? AND uid = ?", orgID, userID).
		Cols("is_public").
		Update(&OrgUser{IsPublic: isPublic})
	return err
}

// GetMemberPublicVisibility gets the public visibility status of a member
func GetMemberPublicVisibility(ctx context.Context, orgID, userID int64) (bool, error) {
	orgUser := new(OrgUser)
	has, err := db.GetEngine(ctx).
		Where("org_id = ? AND uid = ?", orgID, userID).
		Get(orgUser)
	if err != nil {
		return false, err
	}
	if !has {
		return false, nil
	}
	return orgUser.IsPublic, nil
}

// OrgOverviewStats represents statistics for the organization overview
type OrgOverviewStats struct {
	MemberCount     int64
	RepoCount       int64
	PublicRepoCount int64
	TeamCount       int64
}

// GetOrgMemberAndTeamCounts returns member and team counts for an organization
func GetOrgMemberAndTeamCounts(ctx context.Context, orgID int64) (memberCount, teamCount int64, err error) {
	memberCount, err = db.GetEngine(ctx).
		Where("org_id = ?", orgID).
		Count(new(OrgUser))
	if err != nil {
		return 0, 0, err
	}

	teamCount, err = db.GetEngine(ctx).
		Where("org_id = ?", orgID).
		Count(new(Team))
	if err != nil {
		return 0, 0, err
	}

	return memberCount, teamCount, nil
}
