package grpc

import (
	"context"

	userv1 "hyapp.local/api/proto/user/v1"
	"hyapp/pkg/xerr"
	hostservice "hyapp/services/user-service/internal/service/host"
)

// CreateBDLeader 处理 BD Leader/Admin 身份创建。
// 后台 admin 入口和经理中心入口复用同一个事实写入 RPC，具体入口权限在调用方进入该 RPC 前完成。
func (s *Server) CreateBDLeader(ctx context.Context, req *userv1.CreateBDLeaderRequest) (*userv1.CreateBDLeaderResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	profile, err := s.hostSvc.CreateBDLeader(ctx, hostservice.CreateBDLeaderInput{
		CommandID:    req.GetCommandId(),
		AdminUserID:  req.GetAdminUserId(),
		TargetUserID: req.GetTargetUserId(),
		Reason:       req.GetReason(),
		RequestID:    requestIDFromMeta(req.GetMeta()),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.CreateBDLeaderResponse{BdProfile: toProtoBDProfile(profile)}, nil
}

// CreateBD 处理后台创建普通 BD，并绑定有效 BD Leader。
func (s *Server) CreateBD(ctx context.Context, req *userv1.CreateBDRequest) (*userv1.CreateBDResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	profile, err := s.hostSvc.CreateBD(ctx, hostservice.CreateBDInput{
		CommandID:          req.GetCommandId(),
		AdminUserID:        req.GetAdminUserId(),
		TargetUserID:       req.GetTargetUserId(),
		ParentLeaderUserID: req.GetParentLeaderUserId(),
		Reason:             req.GetReason(),
		RequestID:          req.GetMeta().GetRequestId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.CreateBDResponse{BdProfile: toProtoBDProfile(profile)}, nil
}

// SetBDStatus 处理后台停用或恢复 BD/BD Leader。
func (s *Server) SetBDStatus(ctx context.Context, req *userv1.SetBDStatusRequest) (*userv1.SetBDStatusResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	profile, err := s.hostSvc.SetBDStatus(ctx, hostservice.SetBDStatusInput{
		CommandID:    req.GetCommandId(),
		AdminUserID:  req.GetAdminUserId(),
		TargetUserID: req.GetTargetUserId(),
		Role:         req.GetRole(),
		Status:       req.GetStatus(),
		Reason:       req.GetReason(),
		RequestID:    req.GetMeta().GetRequestId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.SetBDStatusResponse{BdProfile: toProtoBDProfile(profile)}, nil
}

// CreateCoinSeller 处理后台创建币商身份；权限和操作审计在 admin-server。
func (s *Server) CreateCoinSeller(ctx context.Context, req *userv1.CreateCoinSellerRequest) (*userv1.CreateCoinSellerResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	profile, err := s.hostSvc.CreateCoinSeller(ctx, hostservice.CreateCoinSellerInput{
		CommandID:               req.GetCommandId(),
		AdminUserID:             req.GetAdminUserId(),
		TargetUserID:            req.GetTargetUserId(),
		Reason:                  req.GetReason(),
		RequestID:               req.GetMeta().GetRequestId(),
		CanManageSubCoinSellers: req.CanManageSubCoinSellers,
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.CreateCoinSellerResponse{CoinSellerProfile: toProtoCoinSellerProfile(profile)}, nil
}

// SetCoinSellerStatus 处理后台启用或停用币商身份。
func (s *Server) SetCoinSellerStatus(ctx context.Context, req *userv1.SetCoinSellerStatusRequest) (*userv1.SetCoinSellerStatusResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	profile, err := s.hostSvc.SetCoinSellerStatus(ctx, hostservice.SetCoinSellerStatusInput{
		CommandID:               req.GetCommandId(),
		AdminUserID:             req.GetAdminUserId(),
		TargetUserID:            req.GetTargetUserId(),
		Status:                  req.GetStatus(),
		Reason:                  req.GetReason(),
		RequestID:               req.GetMeta().GetRequestId(),
		CanManageSubCoinSellers: req.CanManageSubCoinSellers,
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.SetCoinSellerStatusResponse{CoinSellerProfile: toProtoCoinSellerProfile(profile)}, nil
}

// ReviewSubCoinSellerApplication 处理后台对子币商邀请申请的通过或拒绝。
func (s *Server) ReviewSubCoinSellerApplication(ctx context.Context, req *userv1.ReviewSubCoinSellerApplicationRequest) (*userv1.ReviewSubCoinSellerApplicationResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	result, err := s.hostSvc.ReviewSubCoinSellerApplication(ctx, hostservice.ReviewSubCoinSellerApplicationInput{
		CommandID:     req.GetCommandId(),
		AdminUserID:   req.GetAdminUserId(),
		ApplicationID: req.GetApplicationId(),
		Decision:      req.GetDecision(),
		Reason:        req.GetReason(),
		RequestID:     req.GetMeta().GetRequestId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.ReviewSubCoinSellerApplicationResponse{
		Application: toProtoCoinSellerSubApplication(result.Application),
		Relation:    toProtoCoinSellerSubRelation(result.Relation),
		Child:       toProtoCoinSellerListItem(result.Child),
	}, nil
}

// CreateAgency 处理后台直接创建 Agency，并返回 owner host/membership 事实。
func (s *Server) CreateAgency(ctx context.Context, req *userv1.CreateAgencyRequest) (*userv1.CreateAgencyResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	result, err := s.hostSvc.CreateAgency(ctx, hostservice.CreateAgencyInput{
		CommandID:      req.GetCommandId(),
		AdminUserID:    req.GetAdminUserId(),
		OwnerUserID:    req.GetOwnerUserId(),
		ParentBDUserID: req.GetParentBdUserId(),
		Name:           req.GetName(),
		JoinEnabled:    req.GetJoinEnabled(),
		Reason:         req.GetReason(),
		RequestID:      req.GetMeta().GetRequestId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.CreateAgencyResponse{
		Agency:      toProtoAgency(result.Agency),
		HostProfile: toProtoHostProfile(result.HostProfile),
		Membership:  toProtoAgencyMembership(result.Membership),
	}, nil
}

// AdminAddAgencyHost 处理后台直接把用户加入指定 Agency；admin 鉴权和审计仍在 admin-server。
func (s *Server) AdminAddAgencyHost(ctx context.Context, req *userv1.AdminAddAgencyHostRequest) (*userv1.AdminAddAgencyHostResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	result, err := s.hostSvc.AdminAddAgencyHost(ctx, hostservice.AdminAddAgencyHostInput{
		CommandID:    req.GetCommandId(),
		AdminUserID:  req.GetAdminUserId(),
		AgencyID:     req.GetAgencyId(),
		TargetUserID: req.GetTargetUserId(),
		Reason:       req.GetReason(),
		RequestID:    req.GetMeta().GetRequestId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.AdminAddAgencyHostResponse{
		Agency:      toProtoAgency(result.Agency),
		HostProfile: toProtoHostProfile(result.HostProfile),
		Membership:  toProtoAgencyMembership(result.Membership),
	}, nil
}

// CloseAgency 处理后台关闭 Agency；关闭后 App 搜索不会再返回该 Agency。
func (s *Server) CloseAgency(ctx context.Context, req *userv1.CloseAgencyRequest) (*userv1.CloseAgencyResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	agency, err := s.hostSvc.CloseAgency(ctx, hostservice.CloseAgencyInput{
		CommandID:   req.GetCommandId(),
		AdminUserID: req.GetAdminUserId(),
		AgencyID:    req.GetAgencyId(),
		Reason:      req.GetReason(),
		RequestID:   req.GetMeta().GetRequestId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.CloseAgencyResponse{Agency: toProtoAgency(agency)}, nil
}

// DeleteAgency 处理后台删除 Agency 身份；主播身份不删除，只解除当前 Agency 归属。
func (s *Server) DeleteAgency(ctx context.Context, req *userv1.DeleteAgencyRequest) (*userv1.DeleteAgencyResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	agency, err := s.hostSvc.DeleteAgency(ctx, hostservice.DeleteAgencyInput{
		CommandID:   req.GetCommandId(),
		AdminUserID: req.GetAdminUserId(),
		AgencyID:    req.GetAgencyId(),
		Reason:      req.GetReason(),
		RequestID:   req.GetMeta().GetRequestId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.DeleteAgencyResponse{Agency: toProtoAgency(agency)}, nil
}

// SetAgencyStatus 处理后台显式切换 Agency 状态；恢复 closed 不自动开放 join_enabled。
func (s *Server) SetAgencyStatus(ctx context.Context, req *userv1.SetAgencyStatusRequest) (*userv1.SetAgencyStatusResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	agency, err := s.hostSvc.SetAgencyStatus(ctx, hostservice.SetAgencyStatusInput{
		CommandID:   req.GetCommandId(),
		AdminUserID: req.GetAdminUserId(),
		AgencyID:    req.GetAgencyId(),
		Status:      req.GetStatus(),
		Reason:      req.GetReason(),
		RequestID:   req.GetMeta().GetRequestId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.SetAgencyStatusResponse{Agency: toProtoAgency(agency)}, nil
}

// SetAgencyJoinEnabled 处理后台设置 Agency 入会开关。
func (s *Server) SetAgencyJoinEnabled(ctx context.Context, req *userv1.SetAgencyJoinEnabledRequest) (*userv1.SetAgencyJoinEnabledResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	agency, err := s.hostSvc.SetAgencyJoinEnabled(ctx, hostservice.SetAgencyJoinEnabledInput{
		CommandID:   req.GetCommandId(),
		AdminUserID: req.GetAdminUserId(),
		AgencyID:    req.GetAgencyId(),
		JoinEnabled: req.GetJoinEnabled(),
		Reason:      req.GetReason(),
		RequestID:   req.GetMeta().GetRequestId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.SetAgencyJoinEnabledResponse{Agency: toProtoAgency(agency)}, nil
}

// ExternalInviteBD 创建外管操作者直属 BD 的待确认邀请。
func (s *Server) ExternalInviteBD(ctx context.Context, req *userv1.ExternalInviteBDRequest) (*userv1.ExternalInviteBDResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	invitation, err := s.hostSvc.ExternalInviteBD(ctx, hostservice.ExternalInviteBDInput{
		CommandID:        req.GetCommandId(),
		OperatorUserID:   req.GetOperatorUserId(),
		TargetUserID:     req.GetTargetUserId(),
		ExpectedRegionID: req.GetExpectedRegionId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.ExternalInviteBDResponse{Invitation: toProtoRoleInvitation(invitation)}, nil
}

// ExternalInviteAgency 为外管团队内明确选择的 BD 创建 Agency 邀请。
func (s *Server) ExternalInviteAgency(ctx context.Context, req *userv1.ExternalInviteAgencyRequest) (*userv1.ExternalInviteAgencyResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	invitation, err := s.hostSvc.ExternalInviteAgency(ctx, hostservice.ExternalInviteAgencyInput{
		CommandID:         req.GetCommandId(),
		OperatorUserID:    req.GetOperatorUserId(),
		ParentBDUserID:    req.GetParentBdUserId(),
		TargetUserID:      req.GetTargetUserId(),
		AgencyName:        req.GetAgencyName(),
		ScopeOwnerUserIDs: req.GetScopeOwnerUserIds(),
		ExpectedRegionID:  req.GetExpectedRegionId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.ExternalInviteAgencyResponse{Invitation: toProtoRoleInvitation(invitation)}, nil
}

// ExternalInviteHost 为外管团队内明确选择的 Agency 创建 Host 邀请。
func (s *Server) ExternalInviteHost(ctx context.Context, req *userv1.ExternalInviteHostRequest) (*userv1.ExternalInviteHostResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	invitation, err := s.hostSvc.ExternalInviteHost(ctx, hostservice.ExternalInviteHostInput{
		CommandID:         req.GetCommandId(),
		OperatorUserID:    req.GetOperatorUserId(),
		AgencyID:          req.GetAgencyId(),
		TargetUserID:      req.GetTargetUserId(),
		ScopeOwnerUserIDs: req.GetScopeOwnerUserIds(),
		ExpectedRegionID:  req.GetExpectedRegionId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.ExternalInviteHostResponse{Invitation: toProtoRoleInvitation(invitation)}, nil
}

// ListExternalTeamUsers 返回外管 scope 和当前区域交集内的 BD/Agency/Host。
func (s *Server) ListExternalTeamUsers(ctx context.Context, req *userv1.ListExternalTeamUsersRequest) (*userv1.ListExternalTeamUsersResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	result, err := s.hostSvc.ListExternalTeamUsers(ctx, hostservice.ListExternalTeamUsersCommand{
		ScopeOwnerUserIDs: req.GetScopeOwnerUserIds(),
		RegionID:          req.GetRegionId(),
		Role:              req.GetRole(),
		Status:            req.GetStatus(),
		Keyword:           req.GetKeyword(),
		Page:              int(req.GetPage()),
		PageSize:          int(req.GetPageSize()),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &userv1.ListExternalTeamUsersResponse{
		Users:    make([]*userv1.ExternalTeamUser, 0, len(result.Users)),
		Total:    result.Total,
		Page:     int32(result.Page),
		PageSize: int32(result.PageSize),
	}
	for _, user := range result.Users {
		resp.Users = append(resp.Users, toProtoExternalTeamUser(user))
	}
	return resp, nil
}

// SearchExternalInvitationCandidate 精确解析当前区域邀请候选，不暴露模糊用户目录。
func (s *Server) SearchExternalInvitationCandidate(ctx context.Context, req *userv1.SearchExternalInvitationCandidateRequest) (*userv1.SearchExternalInvitationCandidateResponse, error) {
	if s.hostSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
	}
	ctx = contextWithApp(ctx, req.GetMeta())
	user, err := s.hostSvc.SearchExternalInvitationCandidate(ctx, hostservice.SearchExternalInvitationCandidateCommand{
		OperatorUserID:   req.GetOperatorUserId(),
		ExpectedRegionID: req.GetExpectedRegionId(),
		InvitationType:   req.GetInvitationType(),
		Keyword:          req.GetKeyword(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.SearchExternalInvitationCandidateResponse{User: toProtoExternalTeamUser(user)}, nil
}
