package externaladmin

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"

	"hyapp-admin-server/internal/appctx"
	"hyapp-admin-server/internal/modules/shared"
	"hyapp-admin-server/internal/response"

	"github.com/gin-gonic/gin"
)

// optionalPermissionSelection preserves the JSON distinction required by account
// creation: omitted keeps the legacy full snapshot, while an explicit [] creates a
// valid account with no business permissions. JSON null is rejected as ambiguous.
type optionalPermissionSelection struct {
	Value []string
	Set   bool
}

func (selection *optionalPermissionSelection) UnmarshalJSON(body []byte) error {
	selection.Set = true
	body = bytes.TrimSpace(body)
	if bytes.Equal(body, []byte("null")) {
		return errors.New("permissions must be an array")
	}
	var permissions []string
	if err := json.Unmarshal(body, &permissions); err != nil {
		return err
	}
	selection.Value = permissions
	return nil
}

type updatePermissionsRequest struct {
	Permissions      optionalPermissionSelection `json:"permissions"`
	ExpectedRevision uint64                      `json:"expectedRevision"`
}

func (h *Handler) ListPermissionCatalog(c *gin.Context) {
	items := PermissionCatalog()
	response.OK(c, gin.H{"items": items, "total": len(items)})
}

func (h *Handler) GetAccountPermissions(c *gin.Context) {
	id, ok := parseUint64Param(c, "id")
	if !ok {
		return
	}
	permissions, err := h.service.GetAccountPermissions(c.Request.Context(), appctx.FromContext(c.Request.Context()), id)
	if errors.Is(err, ErrAccountNotFound) {
		response.NotFound(c, "外管用户不存在")
		return
	}
	if errors.Is(err, ErrInvalidInput) {
		response.BadRequest(c, "外管用户参数不正确")
		return
	}
	if err != nil {
		response.ServerError(c, "获取外管用户权限失败")
		return
	}
	response.OK(c, permissions)
}

func (h *Handler) UpdateAccountPermissions(c *gin.Context) {
	id, ok := parseUint64Param(c, "id")
	if !ok {
		return
	}
	var request updatePermissionsRequest
	if err := c.ShouldBindJSON(&request); err != nil || !request.Permissions.Set || request.ExpectedRevision == 0 {
		response.BadRequest(c, "权限参数不正确")
		return
	}
	result, err := h.service.UpdateAccountPermissions(c.Request.Context(), appctx.FromContext(c.Request.Context()), id, UpdatePermissionsInput{
		Permissions: request.Permissions.Value, ExpectedRevision: request.ExpectedRevision,
	})
	if errors.Is(err, ErrInvalidPermissions) {
		response.BadRequest(c, permissionValidationMessage(err))
		return
	}
	if errors.Is(err, ErrInvalidInput) {
		response.BadRequest(c, "外管用户参数不正确")
		return
	}
	if errors.Is(err, ErrAccountNotFound) {
		response.NotFound(c, "外管用户不存在")
		return
	}
	if errors.Is(err, ErrPermissionConflict) {
		response.Conflict(c, "外管用户权限已被其他管理员修改，请刷新后重试")
		return
	}
	if err != nil {
		response.ServerError(c, "更新外管用户权限失败")
		return
	}
	shared.OperationLogWithResourceID(
		c,
		h.audit,
		"update-external-admin-user-permissions",
		"external_admin_accounts",
		strconv.FormatUint(id, 10),
		"success",
		fmt.Sprintf(
			"app_code=%s previous_permissions=%s permissions=%s revision=%d changed=%t sessions_revoked=%t",
			result.Account.AppCode,
			strings.Join(result.PreviousPermissions, ","),
			strings.Join(result.Account.Permissions, ","),
			result.Account.PermissionRevision,
			result.Changed,
			result.SessionsRevoked,
		),
	)
	response.OK(c, result.Account)
}
