package userclient

import (
	"context"

	userv1 "hyapp.local/api/proto/user/v1"
)

type PrettyDisplayIDPool struct {
	AppCode          string `json:"app_code"`
	PoolID           string `json:"pool_id"`
	Name             string `json:"name"`
	LevelTrack       string `json:"level_track"`
	MinLevel         int32  `json:"min_level"`
	MaxLevel         int32  `json:"max_level"`
	RuleType         string `json:"rule_type"`
	RuleConfigJSON   string `json:"rule_config_json"`
	Status           string `json:"status"`
	SortOrder        int32  `json:"sort_order"`
	CreatedByAdminID int64  `json:"created_by_admin_id,string"`
	UpdatedByAdminID int64  `json:"updated_by_admin_id,string"`
	CreatedAtMs      int64  `json:"created_at_ms"`
	UpdatedAtMs      int64  `json:"updated_at_ms"`
}

type PrettyDisplayID struct {
	AppCode          string               `json:"app_code"`
	PrettyID         string               `json:"pretty_id"`
	PoolID           string               `json:"pool_id"`
	Source           string               `json:"source"`
	DisplayUserID    string               `json:"display_user_id"`
	Status           string               `json:"status"`
	AssignedUserID   int64                `json:"assigned_user_id,string"`
	AssignedUser     *User                `json:"assigned_user,omitempty"`
	AssignedLeaseID  string               `json:"assigned_lease_id"`
	AssignedAtMs     int64                `json:"assigned_at_ms"`
	ReleasedAtMs     int64                `json:"released_at_ms"`
	ReleaseReason    string               `json:"release_reason"`
	GeneratedBatchID string               `json:"generated_batch_id"`
	CreatedByAdminID int64                `json:"created_by_admin_id,string"`
	CreatedAtMs      int64                `json:"created_at_ms"`
	UpdatedAtMs      int64                `json:"updated_at_ms"`
	Pool             *PrettyDisplayIDPool `json:"pool,omitempty"`
}

type PrettyDisplayIDGenerationBatch struct {
	AppCode              string `json:"app_code"`
	BatchID              string `json:"batch_id"`
	PoolID               string `json:"pool_id"`
	RuleType             string `json:"rule_type"`
	RuleConfigJSON       string `json:"rule_config_json"`
	RequestedCount       int32  `json:"requested_count"`
	GeneratedCount       int32  `json:"generated_count"`
	SkippedConflictCount int32  `json:"skipped_conflict_count"`
	Status               string `json:"status"`
	OperatorAdminID      int64  `json:"operator_admin_id,string"`
	RequestID            string `json:"request_id"`
	CreatedAtMs          int64  `json:"created_at_ms"`
	UpdatedAtMs          int64  `json:"updated_at_ms"`
}

type ListPrettyDisplayIDPoolsRequest struct {
	RequestID  string
	Caller     string
	Status     string
	LevelTrack string
	Page       int32
	PageSize   int32
}

type PrettyDisplayIDPoolRequest struct {
	RequestID       string
	Caller          string
	PoolID          string
	Name            string
	LevelTrack      string
	MinLevel        int32
	MaxLevel        int32
	RuleType        string
	RuleConfigJSON  string
	Status          string
	SortOrder       int32
	OperatorAdminID int64
}

type GeneratePrettyDisplayIDsRequest struct {
	RequestID       string
	Caller          string
	PoolID          string
	RuleType        string
	RuleConfigJSON  string
	Count           int32
	OperatorAdminID int64
}

type ListPrettyDisplayIDsRequest struct {
	RequestID      string
	Caller         string
	PoolID         string
	Source         string
	Status         string
	Keyword        string
	AssignedUserID int64
	Page           int32
	PageSize       int32
}

type SetPrettyDisplayIDStatusRequest struct {
	RequestID       string
	Caller          string
	PrettyID        string
	Status          string
	Reason          string
	OperatorAdminID int64
}

type RecyclePrettyDisplayIDRequest struct {
	RequestID       string
	Caller          string
	PrettyID        string
	Reason          string
	OperatorAdminID int64
}

type AdminGrantPrettyDisplayIDRequest struct {
	RequestID       string
	Caller          string
	TargetUserID    int64
	DisplayUserID   string
	DurationMs      int64
	Reason          string
	OperatorAdminID int64
}

type AdminGrantPrettyDisplayIDResult struct {
	Identity *UserIdentity `json:"identity"`
	PrettyID string        `json:"pretty_id"`
	LeaseID  string        `json:"lease_id"`
}

// 以下方法只做 admin-server 到 user-service 的传输适配：HTTP 层 DTO 保持 snake_case，gRPC 层字段按 proto 命名传递。
func (c *GRPCClient) ListPrettyDisplayIDPools(ctx context.Context, req ListPrettyDisplayIDPoolsRequest) ([]*PrettyDisplayIDPool, int64, error) {
	resp, err := c.prettyClient.ListPrettyDisplayIDPools(ctx, &userv1.ListPrettyDisplayIDPoolsRequest{
		Meta:       requestMeta(ctx, req.RequestID, req.Caller),
		Status:     req.Status,
		LevelTrack: req.LevelTrack,
		Page:       req.Page,
		PageSize:   req.PageSize,
	})
	if err != nil {
		return nil, 0, err
	}
	items := make([]*PrettyDisplayIDPool, 0, len(resp.GetItems()))
	for _, item := range resp.GetItems() {
		items = append(items, fromProtoPrettyDisplayIDPool(item))
	}
	return items, resp.GetTotal(), nil
}

func (c *GRPCClient) CreatePrettyDisplayIDPool(ctx context.Context, req PrettyDisplayIDPoolRequest) (*PrettyDisplayIDPool, error) {
	resp, err := c.prettyClient.CreatePrettyDisplayIDPool(ctx, &userv1.CreatePrettyDisplayIDPoolRequest{
		Meta:            requestMeta(ctx, req.RequestID, req.Caller),
		Name:            req.Name,
		LevelTrack:      req.LevelTrack,
		MinLevel:        req.MinLevel,
		MaxLevel:        req.MaxLevel,
		RuleType:        req.RuleType,
		RuleConfigJson:  req.RuleConfigJSON,
		Status:          req.Status,
		SortOrder:       req.SortOrder,
		OperatorAdminId: req.OperatorAdminID,
	})
	if err != nil {
		return nil, err
	}
	return fromProtoPrettyDisplayIDPool(resp.GetPool()), nil
}

func (c *GRPCClient) UpdatePrettyDisplayIDPool(ctx context.Context, req PrettyDisplayIDPoolRequest) (*PrettyDisplayIDPool, error) {
	resp, err := c.prettyClient.UpdatePrettyDisplayIDPool(ctx, &userv1.UpdatePrettyDisplayIDPoolRequest{
		Meta:            requestMeta(ctx, req.RequestID, req.Caller),
		PoolId:          req.PoolID,
		Name:            req.Name,
		LevelTrack:      req.LevelTrack,
		MinLevel:        req.MinLevel,
		MaxLevel:        req.MaxLevel,
		RuleType:        req.RuleType,
		RuleConfigJson:  req.RuleConfigJSON,
		Status:          req.Status,
		SortOrder:       req.SortOrder,
		OperatorAdminId: req.OperatorAdminID,
	})
	if err != nil {
		return nil, err
	}
	return fromProtoPrettyDisplayIDPool(resp.GetPool()), nil
}

func (c *GRPCClient) GeneratePrettyDisplayIDs(ctx context.Context, req GeneratePrettyDisplayIDsRequest) (*PrettyDisplayIDGenerationBatch, error) {
	// 批量生成的冲突过滤、规则默认值和批次落库都在 user-service，这里不复制业务判断。
	resp, err := c.prettyClient.GeneratePrettyDisplayIDs(ctx, &userv1.GeneratePrettyDisplayIDsRequest{
		Meta:            requestMeta(ctx, req.RequestID, req.Caller),
		PoolId:          req.PoolID,
		RuleType:        req.RuleType,
		RuleConfigJson:  req.RuleConfigJSON,
		Count:           req.Count,
		OperatorAdminId: req.OperatorAdminID,
	})
	if err != nil {
		return nil, err
	}
	return fromProtoPrettyDisplayIDGenerationBatch(resp.GetBatch()), nil
}

func (c *GRPCClient) ListPrettyDisplayIDs(ctx context.Context, req ListPrettyDisplayIDsRequest) ([]*PrettyDisplayID, int64, error) {
	resp, err := c.prettyClient.ListPrettyDisplayIDs(ctx, &userv1.ListPrettyDisplayIDsRequest{
		Meta:           requestMeta(ctx, req.RequestID, req.Caller),
		PoolId:         req.PoolID,
		Source:         req.Source,
		Status:         req.Status,
		Keyword:        req.Keyword,
		AssignedUserId: req.AssignedUserID,
		Page:           req.Page,
		PageSize:       req.PageSize,
	})
	if err != nil {
		return nil, 0, err
	}
	items := make([]*PrettyDisplayID, 0, len(resp.GetItems()))
	for _, item := range resp.GetItems() {
		items = append(items, fromProtoPrettyDisplayID(item))
	}
	return items, resp.GetTotal(), nil
}

func (c *GRPCClient) SetPrettyDisplayIDStatus(ctx context.Context, req SetPrettyDisplayIDStatusRequest) (*PrettyDisplayID, error) {
	resp, err := c.prettyClient.SetPrettyDisplayIDStatus(ctx, &userv1.SetPrettyDisplayIDStatusRequest{
		Meta:            requestMeta(ctx, req.RequestID, req.Caller),
		PrettyId:        req.PrettyID,
		Status:          req.Status,
		OperatorAdminId: req.OperatorAdminID,
		Reason:          req.Reason,
	})
	if err != nil {
		return nil, err
	}
	return fromProtoPrettyDisplayID(resp.GetItem()), nil
}

func (c *GRPCClient) RecyclePrettyDisplayID(ctx context.Context, req RecyclePrettyDisplayIDRequest) (*PrettyDisplayID, error) {
	// 回收必须走 user-service 的后台 RPC，由 owner service 同事务恢复默认短号并释放靓号池记录。
	resp, err := c.prettyClient.RecyclePrettyDisplayID(ctx, &userv1.RecyclePrettyDisplayIDRequest{
		Meta:            requestMeta(ctx, req.RequestID, req.Caller),
		PrettyId:        req.PrettyID,
		Reason:          req.Reason,
		OperatorAdminId: req.OperatorAdminID,
	})
	if err != nil {
		return nil, err
	}
	return fromProtoPrettyDisplayID(resp.GetItem()), nil
}

func (c *GRPCClient) AdminGrantPrettyDisplayID(ctx context.Context, req AdminGrantPrettyDisplayIDRequest) (*AdminGrantPrettyDisplayIDResult, error) {
	// 后台发放返回当前用户身份快照，admin-server 原样转给前端，方便页面确认最终展示号。
	resp, err := c.prettyClient.AdminGrantPrettyDisplayID(ctx, &userv1.AdminGrantPrettyDisplayIDRequest{
		Meta:            requestMeta(ctx, req.RequestID, req.Caller),
		TargetUserId:    req.TargetUserID,
		DisplayUserId:   req.DisplayUserID,
		DurationMs:      req.DurationMs,
		Reason:          req.Reason,
		OperatorAdminId: req.OperatorAdminID,
	})
	if err != nil {
		return nil, err
	}
	return &AdminGrantPrettyDisplayIDResult{
		Identity: fromProtoUserIdentity(resp.GetIdentity()),
		PrettyID: resp.GetPrettyId(),
		LeaseID:  resp.GetLeaseId(),
	}, nil
}

func fromProtoPrettyDisplayIDPool(pool *userv1.PrettyDisplayIDPool) *PrettyDisplayIDPool {
	if pool == nil {
		return nil
	}
	// 转换层保留 int64 的 string JSON tag，避免后台前端在大 ID 上丢精度。
	return &PrettyDisplayIDPool{
		AppCode:          pool.GetAppCode(),
		PoolID:           pool.GetPoolId(),
		Name:             pool.GetName(),
		LevelTrack:       pool.GetLevelTrack(),
		MinLevel:         pool.GetMinLevel(),
		MaxLevel:         pool.GetMaxLevel(),
		RuleType:         pool.GetRuleType(),
		RuleConfigJSON:   pool.GetRuleConfigJson(),
		Status:           pool.GetStatus(),
		SortOrder:        pool.GetSortOrder(),
		CreatedByAdminID: pool.GetCreatedByAdminId(),
		UpdatedByAdminID: pool.GetUpdatedByAdminId(),
		CreatedAtMs:      pool.GetCreatedAtMs(),
		UpdatedAtMs:      pool.GetUpdatedAtMs(),
	}
}

func fromProtoPrettyDisplayID(item *userv1.PrettyDisplayID) *PrettyDisplayID {
	if item == nil {
		return nil
	}
	// pool 可能为空：后台发放的自由靓号没有池归属，列表展示时仍要返回靓号本体。
	return &PrettyDisplayID{
		AppCode:          item.GetAppCode(),
		PrettyID:         item.GetPrettyId(),
		PoolID:           item.GetPoolId(),
		Source:           item.GetSource(),
		DisplayUserID:    item.GetDisplayUserId(),
		Status:           item.GetStatus(),
		AssignedUserID:   item.GetAssignedUserId(),
		AssignedLeaseID:  item.GetAssignedLeaseId(),
		AssignedAtMs:     item.GetAssignedAtMs(),
		ReleasedAtMs:     item.GetReleasedAtMs(),
		ReleaseReason:    item.GetReleaseReason(),
		GeneratedBatchID: item.GetGeneratedBatchId(),
		CreatedByAdminID: item.GetCreatedByAdminId(),
		CreatedAtMs:      item.GetCreatedAtMs(),
		UpdatedAtMs:      item.GetUpdatedAtMs(),
		Pool:             fromProtoPrettyDisplayIDPool(item.GetPool()),
	}
}

func fromProtoPrettyDisplayIDGenerationBatch(batch *userv1.PrettyDisplayIDGenerationBatch) *PrettyDisplayIDGenerationBatch {
	if batch == nil {
		return nil
	}
	return &PrettyDisplayIDGenerationBatch{
		AppCode:              batch.GetAppCode(),
		BatchID:              batch.GetBatchId(),
		PoolID:               batch.GetPoolId(),
		RuleType:             batch.GetRuleType(),
		RuleConfigJSON:       batch.GetRuleConfigJson(),
		RequestedCount:       batch.GetRequestedCount(),
		GeneratedCount:       batch.GetGeneratedCount(),
		SkippedConflictCount: batch.GetSkippedConflictCount(),
		Status:               batch.GetStatus(),
		OperatorAdminID:      batch.GetOperatorAdminId(),
		RequestID:            batch.GetRequestId(),
		CreatedAtMs:          batch.GetCreatedAtMs(),
		UpdatedAtMs:          batch.GetUpdatedAtMs(),
	}
}
