// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2020 The Gitea Authors.
// SPDX-License-Identifier: MIT

package org

import (
	"errors"
	"net/http"

	"gitea.dev/models/organization"
	user_model "gitea.dev/models/user"
	"gitea.dev/modules/log"
	"gitea.dev/modules/setting"
	"gitea.dev/modules/templates"
	"gitea.dev/modules/util"
	shared_user "gitea.dev/routers/web/shared/user"
	"gitea.dev/services/context"
	org_service "gitea.dev/services/org"
)

const (
	// tplMembers template for organization members page
	tplMembers templates.TplName = "org/member/members"
)

// Members render organization users page
func Members(ctx *context.Context) {
	org := ctx.Org.Organization
	ctx.Data["Title"] = org.FullName
	ctx.Data["PageIsOrgMembers"] = true

	page := max(ctx.FormInt("page"), 1)
	keyword := ctx.FormTrim("q")
	ctx.Data["Keyword"] = keyword

	opts := &organization.FindOrgMembersOpts{
		Doer:    ctx.Doer,
		OrgID:   org.ID,
		Keyword: keyword,
	}

	if ctx.Doer != nil {
		isMember, err := ctx.Org.Organization.IsOrgMember(ctx, ctx.Doer.ID)
		if err != nil {
			ctx.ServerError("IsOrgMember", err)
			return
		}
		opts.IsDoerMember = isMember
	}
	ctx.Data["PublicOnly"] = opts.PublicOnly()

	total, err := organization.CountOrgMembers(ctx, opts)
	if err != nil {
		ctx.ServerError("CountOrgMembers", err)
		return
	}

	if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
		ctx.ServerError("RenderUserOrgHeader", err)
		return
	}

	pageSize := setting.UI.MembersPagingNum
	pager := context.NewPagination(total, pageSize, page, 5)
	pager.AddParamFromRequest(ctx.Req)
	opts.ListOptions.Page = pager.Paginater.Current()
	opts.ListOptions.PageSize = pageSize
	members, membersIsPublic, err := organization.FindOrgMembers(ctx, opts)
	if err != nil {
		ctx.ServerError("GetMembers", err)
		return
	}
	ctx.Data["Page"] = pager
	ctx.Data["Members"] = members
	ctx.Data["MembersIsPublicMember"] = membersIsPublic
	ctx.Data["MembersIsUserOrgOwner"] = organization.IsUserOrgOwner(ctx, members, org.ID)
	ctx.Data["MembersTwoFaStatus"] = members.GetTwoFaStatus(ctx)

	ctx.HTML(http.StatusOK, tplMembers)
}

// MembersAction response for operation to a member of organization
func MembersAction(ctx *context.Context) {
	member, err := user_model.GetUserByID(ctx, ctx.FormInt64("uid"))
	if errors.Is(err, util.ErrNotExist) {
		ctx.HTTPError(http.StatusNotFound)
		return
	} else if err != nil {
		ctx.ServerError("GetUserByID", err)
		return
	}

	org := ctx.Org.Organization

	switch ctx.PathParam("action") {
	case "private":
		if ctx.Doer.ID != member.ID && !ctx.Org.IsOwner {
			ctx.HTTPError(http.StatusNotFound)
			return
		}
		err = organization.ChangeOrgUserStatus(ctx, org.ID, member.ID, false)
	case "public":
		if ctx.Doer.ID != member.ID && !ctx.Org.IsOwner {
			ctx.HTTPError(http.StatusNotFound)
			return
		}
		err = organization.ChangeOrgUserStatus(ctx, org.ID, member.ID, true)
	case "remove":
		if !ctx.Org.IsOwner {
			ctx.HTTPError(http.StatusNotFound)
			return
		}
		err = org_service.RemoveOrgUser(ctx, org, member)
	case "leave":
		err = org_service.RemoveOrgUser(ctx, org, ctx.Doer)
		if err == nil {
			ctx.Flash.Success(ctx.Tr("form.organization_leave_success", org.DisplayName()))
			ctx.JSONRedirect(setting.AppSubURL + "/")
			return
		}
	}

	if err == nil {
		ctx.JSONOK()
		return
	}

	if organization.IsErrLastOrgOwner(err) {
		ctx.JSONError(ctx.Tr("form.last_org_owner"))
		return
	}

	log.Error("Action(%s): %v", ctx.PathParam("action"), err)
	ctx.JSONError(err.Error()) // FIXME: legacy logic, errors are handled together, it's not right, need to distinguish between different errors
}
