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

package org

import (
	"net/http"

	"code.gitea.io/gitea/models/organization"
	user_model "code.gitea.io/gitea/models/user"
	api "code.gitea.io/gitea/modules/structs"
	"code.gitea.io/gitea/services/context"
	"code.gitea.io/gitea/services/convert"
	org_service "code.gitea.io/gitea/services/org"
)

// GetOverview returns the organization overview for the profile page
func GetOverview(ctx *context.APIContext) {
	// swagger:operation GET /orgs/{org}/overview organization orgGetOverview
	// ---
	// summary: Get organization overview
	// produces:
	// - application/json
	// parameters:
	// - name: org
	//   in: path
	//   description: name of the organization
	//   type: string
	//   required: true
	// responses:
	//   "200":
	//     "$ref": "#/responses/OrgOverview"
	//   "404":
	//     "$ref": "#/responses/notFound"

	org := ctx.Org.Organization

	// Get pinned repos
	pinnedRepos, err := org_service.GetOrgPinnedReposWithDetails(ctx, org.ID)
	if err != nil {
		ctx.APIErrorInternal(err)
		return
	}

	// Get pinned groups
	pinnedGroups, err := organization.GetOrgPinnedGroups(ctx, org.ID)
	if err != nil {
		ctx.APIErrorInternal(err)
		return
	}

	// Get public members (limit to 12 for overview)
	publicMembers, totalMembers, err := organization.GetPublicOrgMembers(ctx, org.ID, 12)
	if err != nil {
		ctx.APIErrorInternal(err)
		return
	}

	// Get stats
	stats, err := org_service.GetOrgOverviewStats(ctx, org.ID)
	if err != nil {
		ctx.APIErrorInternal(err)
		return
	}

	// Build API response
	apiPinnedRepos := make([]*api.OrgPinnedRepo, 0, len(pinnedRepos))
	for _, p := range pinnedRepos {
		if p.Repo == nil {
			continue
		}
		apiPinnedRepos = append(apiPinnedRepos, convertOrgPinnedRepo(ctx, p))
	}

	apiPinnedGroups := make([]*api.OrgPinnedGroup, len(pinnedGroups))
	for i, g := range pinnedGroups {
		apiPinnedGroups[i] = convertOrgPinnedGroup(g)
	}

	apiPublicMembers := make([]*api.OrgPublicMember, len(publicMembers))
	for i, m := range publicMembers {
		apiPublicMembers[i] = &api.OrgPublicMember{
			User: convert.ToUser(ctx, m.User, ctx.Doer),
			Role: m.Role,
		}
	}

	overview := &api.OrgOverview{
		Organization:  convert.ToOrganization(ctx, org),
		PinnedRepos:   apiPinnedRepos,
		PinnedGroups:  apiPinnedGroups,
		PublicMembers: apiPublicMembers,
		TotalMembers:  totalMembers,
		Stats: &api.OrgOverviewStats{
			MemberCount:     stats.MemberCount,
			RepoCount:       stats.RepoCount,
			PublicRepoCount: stats.PublicRepoCount,
			TeamCount:       stats.TeamCount,
		},
	}

	ctx.JSON(http.StatusOK, overview)
}

// ListPublicMembersWithRoles returns the public members of an organization with their roles
func ListPublicMembersWithRoles(ctx *context.APIContext) {
	// swagger:operation GET /orgs/{org}/public_members/roles organization orgListPublicMembersWithRoles
	// ---
	// summary: List an organization's public members with their roles
	// produces:
	// - application/json
	// parameters:
	// - name: org
	//   in: path
	//   description: name of the organization
	//   type: string
	//   required: true
	// - name: page
	//   in: query
	//   description: page number of results to return (1-based)
	//   type: integer
	// - name: limit
	//   in: query
	//   description: page size of results
	//   type: integer
	// responses:
	//   "200":
	//     "$ref": "#/responses/OrgPublicMemberList"
	//   "404":
	//     "$ref": "#/responses/notFound"

	// Get all public members (no limit)
	publicMembers, total, err := organization.GetPublicOrgMembers(ctx, ctx.Org.Organization.ID, 0)
	if err != nil {
		ctx.APIErrorInternal(err)
		return
	}

	apiPublicMembers := make([]*api.OrgPublicMember, len(publicMembers))
	for i, m := range publicMembers {
		apiPublicMembers[i] = &api.OrgPublicMember{
			User: convert.ToUser(ctx, m.User, ctx.Doer),
			Role: m.Role,
		}
	}

	ctx.SetTotalCountHeader(total)
	ctx.JSON(http.StatusOK, apiPublicMembers)
}

// setPublicMembershipVisibility is a helper for setting member public visibility
func setPublicMembershipVisibility(ctx *context.APIContext, visible bool) {
	username := ctx.PathParam("username")

	// Users can only change their own visibility
	if ctx.Doer.Name != username {
		isOwner, err := organization.IsOrganizationOwner(ctx, ctx.Org.Organization.ID, ctx.Doer.ID)
		if err != nil {
			ctx.APIErrorInternal(err)
			return
		}
		if !isOwner {
			ctx.APIError(http.StatusForbidden, "You can only change your own public membership visibility")
			return
		}
	}

	// Get the user
	user, err := user_model.GetUserByName(ctx, username)
	if err != nil {
		if user_model.IsErrUserNotExist(err) {
			ctx.APIErrorNotFound("GetUserByName", err)
			return
		}
		ctx.APIErrorInternal(err)
		return
	}

	// Verify user is a member
	isMember, err := organization.IsOrganizationMember(ctx, ctx.Org.Organization.ID, user.ID)
	if err != nil {
		ctx.APIErrorInternal(err)
		return
	}
	if !isMember {
		ctx.APIErrorNotFound()
		return
	}

	if err := organization.SetMemberPublicVisibility(ctx, ctx.Org.Organization.ID, user.ID, visible); err != nil {
		ctx.APIErrorInternal(err)
		return
	}

	ctx.Status(http.StatusNoContent)
}

// SetPublicMembership sets the public visibility of a member
func SetPublicMembership(ctx *context.APIContext) {
	// swagger:operation PUT /orgs/{org}/public_members/{username} organization orgSetPublicMembership
	// ---
	// summary: Set public membership visibility for a user
	// produces:
	// - application/json
	// parameters:
	// - name: org
	//   in: path
	//   description: name of the organization
	//   type: string
	//   required: true
	// - name: username
	//   in: path
	//   description: username of the user
	//   type: string
	//   required: true
	// responses:
	//   "204":
	//     "$ref": "#/responses/empty"
	//   "403":
	//     "$ref": "#/responses/forbidden"
	//   "404":
	//     "$ref": "#/responses/notFound"

	setPublicMembershipVisibility(ctx, true)
}

// RemovePublicMembership removes the public visibility of a member
func RemovePublicMembership(ctx *context.APIContext) {
	// swagger:operation DELETE /orgs/{org}/public_members/{username} organization orgRemovePublicMembership
	// ---
	// summary: Remove public membership visibility for a user
	// produces:
	// - application/json
	// parameters:
	// - name: org
	//   in: path
	//   description: name of the organization
	//   type: string
	//   required: true
	// - name: username
	//   in: path
	//   description: username of the user
	//   type: string
	//   required: true
	// responses:
	//   "204":
	//     "$ref": "#/responses/empty"
	//   "403":
	//     "$ref": "#/responses/forbidden"
	//   "404":
	//     "$ref": "#/responses/notFound"

	setPublicMembershipVisibility(ctx, false)
}
