package hostorg

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

	"hyapp-admin-server/internal/modules/shared"
)

// flexibleInt64 只用于 admin HTTP 请求入参：前端新合约会按字符串提交用户长 ID，旧页面或脚本可能仍提交 JSON number。
// 这里同时接受两种形态，进入业务层前仍落成 int64，保证后续短 ID 解析、RPC 参数和审计日志不出现两套类型分支。
type flexibleInt64 int64

func (v *flexibleInt64) UnmarshalJSON(data []byte) error {
	raw := strings.TrimSpace(string(data))
	if raw == "" || raw == "null" {
		*v = 0
		return nil
	}
	if strings.HasPrefix(raw, `"`) {
		var text string
		if err := json.Unmarshal(data, &text); err != nil {
			return err
		}
		raw = strings.TrimSpace(text)
		if raw == "" {
			*v = 0
			return nil
		}
	}
	parsed, err := strconv.ParseInt(raw, 10, 64)
	if err != nil {
		return fmt.Errorf("invalid int64 id %q", raw)
	}
	*v = flexibleInt64(parsed)
	return nil
}

func (v flexibleInt64) Int64() int64 {
	return int64(v)
}

type listQuery struct {
	Page               int
	PageSize           int
	Keyword            string
	UserFilter         shared.UserIdentityFilter
	OwnerFilter        shared.UserIdentityFilter
	ParentLeaderFilter shared.UserIdentityFilter
	ParentBDFilter     shared.UserIdentityFilter
	Status             string
	RegionID           int64
	AgencyID           int64
	ParentBDUserID     int64
	ParentLeaderUserID int64
	ParentUserID       int64
	TargetUserID       int64
	SortBy             string
	SortDirection      string
}

type createBDLeaderRequest struct {
	CommandID     string        `json:"commandId" binding:"required"`
	TargetUserID  flexibleInt64 `json:"targetUserId" binding:"required"`
	PositionAlias string        `json:"positionAlias"`
	Reason        string        `json:"reason"`
}

type createManagerRequest struct {
	Contact                string        `json:"contact"`
	TargetUserID           flexibleInt64 `json:"targetUserId" binding:"required"`
	CanGrantAvatarFrame    *bool         `json:"canGrantAvatarFrame"`
	CanGrantVehicle        *bool         `json:"canGrantVehicle"`
	CanGrantBadge          *bool         `json:"canGrantBadge"`
	CanGrantVIP            *bool         `json:"canGrantVip"`
	CanUpdateUserLevel     *bool         `json:"canUpdateUserLevel"`
	CanAddBDLeader         *bool         `json:"canAddBdLeader"`
	CanManageCrossRegion   *bool         `json:"canManageCrossRegion"`
	LegacyBDLeaderInRegion *bool         `json:"canAddBdLeaderInRegion"`
	CanAddAdmin            *bool         `json:"canAddAdmin"`
	CanAddSuperadmin       *bool         `json:"canAddSuperadmin"`
	CanBlockUser           *bool         `json:"canBlockUser"`
	CanTransferCountry     *bool         `json:"canTransferUserCountry"`
}

type updateManagerRequest struct {
	Contact                *string `json:"contact"`
	Status                 *string `json:"status"`
	CanGrantAvatarFrame    *bool   `json:"canGrantAvatarFrame"`
	CanGrantVehicle        *bool   `json:"canGrantVehicle"`
	CanGrantBadge          *bool   `json:"canGrantBadge"`
	CanGrantVIP            *bool   `json:"canGrantVip"`
	CanUpdateUserLevel     *bool   `json:"canUpdateUserLevel"`
	CanAddBDLeader         *bool   `json:"canAddBdLeader"`
	CanManageCrossRegion   *bool   `json:"canManageCrossRegion"`
	LegacyBDLeaderInRegion *bool   `json:"canAddBdLeaderInRegion"`
	CanAddAdmin            *bool   `json:"canAddAdmin"`
	CanAddSuperadmin       *bool   `json:"canAddSuperadmin"`
	CanBlockUser           *bool   `json:"canBlockUser"`
	CanTransferCountry     *bool   `json:"canTransferUserCountry"`
}

func (r updateManagerRequest) appendStatusAssignment(assignments *[]string, args *[]any) error {
	if r.Status == nil {
		return nil
	}
	status := strings.ToLower(strings.TrimSpace(*r.Status))
	if status == "" {
		return nil
	}
	if status != "active" && status != "disabled" {
		return fmt.Errorf("manager status is invalid")
	}
	// 经理状态属于 manager_profiles 自身身份开关；停用经理只关闭经理中心身份，不改用户主状态或其他 Host/BD 关系。
	*assignments = append(*assignments, "status = ?")
	*args = append(*args, status)
	return nil
}

type managerPermissions struct {
	CanGrantAvatarFrame  bool
	CanGrantVehicle      bool
	CanGrantBadge        bool
	CanGrantVIP          bool
	CanUpdateUserLevel   bool
	CanAddBDLeader       bool
	CanManageCrossRegion bool
	CanAddAdmin          bool
	CanAddSuperadmin     bool
	CanBlockUser         bool
	CanTransferCountry   bool
}

func (r createManagerRequest) permissionsWithDefault() managerPermissions {
	return managerPermissions{
		CanGrantAvatarFrame:  boolDefaultTrue(r.CanGrantAvatarFrame),
		CanGrantVehicle:      boolDefaultTrue(r.CanGrantVehicle),
		CanGrantBadge:        boolDefaultTrue(r.CanGrantBadge),
		CanGrantVIP:          boolDefaultTrue(r.CanGrantVIP),
		CanUpdateUserLevel:   boolDefaultTrue(r.CanUpdateUserLevel),
		CanAddBDLeader:       boolDefaultTrue(r.CanAddBDLeader),
		CanManageCrossRegion: boolDefaultFalse(firstBool(r.CanManageCrossRegion, r.LegacyBDLeaderInRegion)),
		CanAddAdmin:          boolDefaultTrue(r.CanAddAdmin),
		CanAddSuperadmin:     boolDefaultTrue(r.CanAddSuperadmin),
		CanBlockUser:         boolDefaultTrue(r.CanBlockUser),
		CanTransferCountry:   boolDefaultTrue(r.CanTransferCountry),
	}
}

func (r updateManagerRequest) appendPermissionAssignments(assignments *[]string, args *[]any) {
	appendBoolAssignment(assignments, args, "can_grant_avatar_frame", r.CanGrantAvatarFrame)
	appendBoolAssignment(assignments, args, "can_grant_vehicle", r.CanGrantVehicle)
	appendBoolAssignment(assignments, args, "can_grant_badge", r.CanGrantBadge)
	appendBoolAssignment(assignments, args, "can_grant_vip", r.CanGrantVIP)
	appendBoolAssignment(assignments, args, "can_update_user_level", r.CanUpdateUserLevel)
	appendBoolAssignment(assignments, args, "can_add_bd_leader", r.CanAddBDLeader)
	appendBoolAssignment(assignments, args, "can_manage_cross_region", firstBool(r.CanManageCrossRegion, r.LegacyBDLeaderInRegion))
	appendBoolAssignment(assignments, args, "can_add_admin", r.CanAddAdmin)
	appendBoolAssignment(assignments, args, "can_add_superadmin", r.CanAddSuperadmin)
	appendBoolAssignment(assignments, args, "can_block_user", r.CanBlockUser)
	appendBoolAssignment(assignments, args, "can_transfer_user_country", r.CanTransferCountry)
}

func appendBoolAssignment(assignments *[]string, args *[]any, column string, value *bool) {
	if value == nil {
		return
	}
	*assignments = append(*assignments, column+" = ?")
	*args = append(*args, *value)
}

func boolDefaultTrue(value *bool) bool {
	return value == nil || *value
}

func boolDefaultFalse(value *bool) bool {
	return value != nil && *value
}

func firstBool(primary *bool, fallback *bool) *bool {
	if primary != nil {
		return primary
	}
	return fallback
}

type createBDRequest struct {
	CommandID          string        `json:"commandId" binding:"required"`
	TargetUserID       flexibleInt64 `json:"targetUserId" binding:"required"`
	ParentLeaderUserID flexibleInt64 `json:"parentLeaderUserId"`
	Reason             string        `json:"reason"`
}

type bdStatusRequest struct {
	CommandID string `json:"commandId" binding:"required"`
	Status    string `json:"status" binding:"required"`
	Reason    string `json:"reason"`
}

type bdLeaderPositionAliasRequest struct {
	CommandID     string `json:"commandId" binding:"required"`
	PositionAlias string `json:"positionAlias"`
	Reason        string `json:"reason"`
}

type createCoinSellerRequest struct {
	CommandID               string        `json:"commandId" binding:"required"`
	Contact                 string        `json:"contact"`
	TargetUserID            flexibleInt64 `json:"targetUserId" binding:"required"`
	Reason                  string        `json:"reason"`
	CanManageSubCoinSellers *bool         `json:"canManageSubCoinSellers"`
}

type coinSellerStatusRequest struct {
	CommandID               string  `json:"commandId" binding:"required"`
	Contact                 *string `json:"contact"`
	Status                  string  `json:"status" binding:"required"`
	Reason                  string  `json:"reason"`
	CanManageSubCoinSellers *bool   `json:"canManageSubCoinSellers"`
}

type coinSellerSubApplicationReviewRequest struct {
	CommandID string `json:"commandId" binding:"required"`
	Reason    string `json:"reason"`
}

type coinSellerStockCreditRequest struct {
	CommandID      string `json:"commandId" binding:"required"`
	Type           string `json:"type" binding:"required"`
	CoinAmount     int64  `json:"coinAmount" binding:"required"`
	RechargeAmount string `json:"rechargeAmount"`
	PaymentRef     string `json:"paymentRef"`
	EvidenceRef    string `json:"evidenceRef"`
	Reason         string `json:"reason"`
}

type coinSellerStockDebitRequest struct {
	CommandID      string `json:"commandId" binding:"required"`
	CoinAmount     int64  `json:"coinAmount" binding:"required"`
	RechargeAmount string `json:"rechargeAmount" binding:"required"`
	EvidenceRef    string `json:"evidenceRef"`
	Reason         string `json:"reason" binding:"required"`
}

type replaceCoinSellerSalaryRatesRequest struct {
	Tiers []coinSellerSalaryRateTierRequest `json:"tiers" binding:"required"`
}

type coinSellerSalaryRateTierRequest struct {
	MinUSD      string `json:"minUsd"`
	MaxUSD      string `json:"maxUsd"`
	MinUSDMinor int64  `json:"minUsdMinor"`
	MaxUSDMinor int64  `json:"maxUsdMinor"`
	CoinPerUSD  int64  `json:"coinPerUsd" binding:"required"`
	Enabled     *bool  `json:"enabled"`
	Status      string `json:"status"`
	SortOrder   int    `json:"sortOrder"`
}

type createAgencyRequest struct {
	CommandID      string        `json:"commandId" binding:"required"`
	OwnerUserID    flexibleInt64 `json:"ownerUserId" binding:"required"`
	ParentBDUserID flexibleInt64 `json:"parentBdUserId"`
	Name           string        `json:"name"`
	JoinEnabled    *bool         `json:"joinEnabled" binding:"required"`
	Reason         string        `json:"reason"`
}

type agencyHostAddRequest struct {
	CommandID    string        `json:"commandId" binding:"required"`
	TargetUserID flexibleInt64 `json:"targetUserId" binding:"required"`
	Reason       string        `json:"reason"`
}

type agencyJoinEnabledRequest struct {
	CommandID   string `json:"commandId" binding:"required"`
	JoinEnabled *bool  `json:"joinEnabled" binding:"required"`
	Reason      string `json:"reason"`
}

type agencyCloseRequest struct {
	CommandID string `json:"commandId" binding:"required"`
	Reason    string `json:"reason"`
}

type agencyStatusRequest struct {
	CommandID string `json:"commandId" binding:"required"`
	Status    string `json:"status" binding:"required"`
	Reason    string `json:"reason"`
}

type agencyDeleteRequest struct {
	CommandID string `json:"commandId" binding:"required"`
	Reason    string `json:"reason"`
}
