package host

import (
	"context"
	"database/sql"
	"fmt"
	"strings"

	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	hostdomain "hyapp/services/user-service/internal/domain/host"
	hostservice "hyapp/services/user-service/internal/service/host"
)

// SearchAgencies 返回用户当前区域内可加入的有效 Agency。
func (r *Repository) SearchAgencies(ctx context.Context, command hostservice.SearchAgenciesCommand) ([]hostdomain.Agency, error) {
	regionID, err := r.userRegion(ctx, r.db, command.UserID, "")
	if err != nil {
		return nil, err
	}
	if regionID <= 0 {
		// 区域是 Agency 搜索和申请的硬边界，缺失时不能退化成全局搜索。
		return nil, xerr.New(xerr.InvalidArgument, "user region is required")
	}

	query := fmt.Sprintf(`
		SELECT %s
		FROM agencies
		WHERE app_code = ? AND region_id = ? AND status = ? AND join_enabled = TRUE
	`, agencyColumns)
	args := []any{appcode.FromContext(ctx), regionID, hostdomain.AgencyStatusActive}
	if strings.TrimSpace(command.Keyword) != "" {
		query += " AND name LIKE ?"
		args = append(args, "%"+strings.TrimSpace(command.Keyword)+"%")
	}
	query += " ORDER BY created_at_ms DESC, agency_id DESC LIMIT ?"
	args = append(args, command.PageSize)

	rows, err := r.db.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	agencies := make([]hostdomain.Agency, 0, command.PageSize)
	for rows.Next() {
		agency, err := scanAgency(rows)
		if err != nil {
			return nil, err
		}
		agencies = append(agencies, agency)
	}

	return agencies, rows.Err()
}

// GetHostProfile 读取 Host 身份事实。
func (r *Repository) GetHostProfile(ctx context.Context, userID int64) (hostdomain.HostProfile, error) {
	return queryHostProfile(ctx, r.db, "WHERE user_id = ?", userID)
}

// GetBDProfile 读取 BD 身份事实。
func (r *Repository) GetBDProfile(ctx context.Context, userID int64) (hostdomain.BDProfile, error) {
	return queryBDProfile(ctx, r.db, "WHERE user_id = ?", userID)
}

// GetCoinSellerProfile 读取币商身份事实。
func (r *Repository) GetCoinSellerProfile(ctx context.Context, userID int64) (hostdomain.CoinSellerProfile, error) {
	return queryCoinSellerProfile(ctx, r.db, "WHERE user_id = ?", userID)
}

// GetUserRoleSummary 用一组索引点查构造我的页角色摘要。
// 摘要只表达入口显隐需要的当前身份，不加载成员列表、团队统计或薪资数据。
func (r *Repository) GetUserRoleSummary(ctx context.Context, userID int64) (hostdomain.UserRoleSummary, error) {
	app := appcode.FromContext(ctx)
	summary := hostdomain.UserRoleSummary{UserID: userID}
	var hostStatus string
	var hostSource string
	var hostAgencyID int64
	var ownerAgencyID int64
	var bdUserID int64
	var bdRole string
	var bdStatus string
	var coinSellerStatus string
	var merchantAssetType string

	err := r.db.QueryRowContext(ctx, `
		SELECT
		  COALESCE(h.status, ''),
		  COALESCE(h.source, ''),
		  COALESCE(h.current_agency_id, 0),
		  COALESCE(a.agency_id, 0),
		  COALESCE(b.user_id, 0),
		  COALESCE(b.role, ''),
		  COALESCE(b.status, ''),
		  COALESCE(c.status, ''),
		  COALESCE(c.merchant_asset_type, '')
		FROM (SELECT ? AS user_id) u
		LEFT JOIN host_profiles h
		  ON h.app_code = ? AND h.user_id = u.user_id
		LEFT JOIN agencies a
		  ON a.app_code = ? AND a.owner_user_id = u.user_id AND a.status = ?
		LEFT JOIN bd_profiles b
		  ON b.app_code = ? AND b.user_id = u.user_id
		LEFT JOIN coin_seller_profiles c
		  ON c.app_code = ? AND c.user_id = u.user_id`,
		userID,
		app,
		app, hostdomain.AgencyStatusActive,
		app,
		app,
	).Scan(&hostStatus, &hostSource, &hostAgencyID, &ownerAgencyID, &bdUserID, &bdRole, &bdStatus, &coinSellerStatus, &merchantAssetType)
	if err != nil {
		return hostdomain.UserRoleSummary{}, err
	}

	summary.HostStatus = hostStatus
	summary.IsHost = hostStatus == hostdomain.HostStatusActive
	if ownerAgencyID > 0 {
		summary.AgencyID = ownerAgencyID
	} else {
		summary.AgencyID = hostAgencyID
	}
	summary.IsAgency = ownerAgencyID > 0 || (summary.IsHost && (hostSource == hostdomain.HostSourceAgencyInvitation || hostSource == hostdomain.HostSourceAdminCreateAgency))
	summary.BDStatus = bdStatus
	if bdUserID > 0 && bdStatus == hostdomain.BDStatusActive {
		summary.BDID = bdUserID
		switch bdRole {
		case hostdomain.BDRoleLeader:
			summary.IsBD = true
			summary.IsBDLeader = true
		case hostdomain.BDRoleBD:
			summary.IsBD = true
		}
	}
	summary.CoinSellerStatus = coinSellerStatus
	summary.IsCoinSeller = coinSellerStatus == hostdomain.CoinSellerStatusActive && merchantAssetType == hostdomain.CoinSellerMerchantAssetType
	if err := r.db.QueryRowContext(ctx, `
		SELECT COUNT(*)
		FROM role_invitations
		WHERE app_code = ? AND target_user_id = ? AND status = ?`,
		app, userID, hostdomain.InvitationStatusPending,
	).Scan(&summary.PendingRoleInvitations); err != nil {
		return hostdomain.UserRoleSummary{}, err
	}

	return summary, nil
}

// HasActiveAgencyOwner 精确判断用户是否为 active Agency owner。
// 普通 Agency 成员会在 UserRoleSummary 中有 Agency 入口，但不能获得经理中心资源赠送权限。
func (r *Repository) HasActiveAgencyOwner(ctx context.Context, userID int64) (int64, bool, error) {
	agency, ok, err := queryActiveAgencyByOwner(ctx, r.db, userID, false)
	if err != nil || !ok {
		return 0, ok, err
	}
	return agency.AgencyID, true, nil
}

// ListAgencyMembers 读取 Agency 成员关系列表。
func (r *Repository) ListAgencyMembers(ctx context.Context, agencyID int64, status string) ([]hostdomain.AgencyMembership, error) {
	query := fmt.Sprintf(`SELECT %s FROM agency_memberships WHERE app_code = ? AND agency_id = ?`, agencyMembershipColumns)
	args := []any{appcode.FromContext(ctx), agencyID}
	if status != "" {
		query += " AND status = ?"
		args = append(args, status)
	}
	query += " ORDER BY joined_at_ms DESC, membership_id DESC"
	return queryAgencyMemberships(ctx, r.db, query, args...)
}

// ListAgencyApplications 读取 Agency 申请列表。
func (r *Repository) ListAgencyApplications(ctx context.Context, agencyID int64, status string) ([]hostdomain.AgencyApplication, error) {
	query := fmt.Sprintf(`SELECT %s FROM agency_applications WHERE app_code = ? AND agency_id = ?`, agencyApplicationColumns)
	args := []any{appcode.FromContext(ctx), agencyID}
	if status != "" {
		query += " AND status = ?"
		args = append(args, status)
	}
	query += " ORDER BY created_at_ms DESC, application_id DESC"
	return queryAgencyApplications(ctx, r.db, query, args...)
}

func queryHostProfile(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.HostProfile, error) {
	clause, args = appScopedClause(ctx, clause, args...)
	profile, err := scanHostProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM host_profiles %s`, hostProfileColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.HostProfile{}, xerr.New(xerr.NotFound, "host profile not found")
	}
	return profile, err
}

func queryHostProfileMaybe(ctx context.Context, q sqlQueryer, userID int64, lock bool) (hostdomain.HostProfile, bool, error) {
	clause := "WHERE user_id = ? AND status = ?"
	if lock {
		clause += " FOR UPDATE"
	}
	clause, args := appScopedClause(ctx, clause, userID, hostdomain.HostStatusActive)
	profile, err := scanHostProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM host_profiles %s`, hostProfileColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.HostProfile{}, false, nil
	}
	if err != nil {
		return hostdomain.HostProfile{}, false, err
	}
	return profile, true, nil
}

func queryHostProfileByUserMaybe(ctx context.Context, q sqlQueryer, userID int64, lock bool) (hostdomain.HostProfile, bool, error) {
	clause := "WHERE user_id = ?"
	if lock {
		// 后台创建 Agency owner 时需要覆盖 active/disabled 任意主播身份行，避免重复插入主键。
		clause += " FOR UPDATE"
	}
	clause, args := appScopedClause(ctx, clause, userID)
	profile, err := scanHostProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM host_profiles %s`, hostProfileColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.HostProfile{}, false, nil
	}
	if err != nil {
		return hostdomain.HostProfile{}, false, err
	}
	return profile, true, nil
}

func scanHostProfile(scanner rowScanner) (hostdomain.HostProfile, error) {
	var profile hostdomain.HostProfile
	err := scanner.Scan(
		&profile.UserID,
		&profile.Status,
		&profile.RegionID,
		&profile.CurrentAgencyID,
		&profile.CurrentMembershipID,
		&profile.Source,
		&profile.FirstBecameHostAtMs,
		&profile.CreatedAtMs,
		&profile.UpdatedAtMs,
	)
	return profile, err
}

func queryAgency(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.Agency, error) {
	clause, args = appScopedClause(ctx, clause, args...)
	agency, err := scanAgency(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM agencies %s`, agencyColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.Agency{}, xerr.New(xerr.NotFound, "agency not found")
	}
	return agency, err
}

func queryActiveAgencyByOwner(ctx context.Context, q sqlQueryer, ownerUserID int64, lock bool) (hostdomain.Agency, bool, error) {
	clause := "WHERE owner_user_id = ? AND status = ?"
	if lock {
		clause += " FOR UPDATE"
	}
	clause, args := appScopedClause(ctx, clause, ownerUserID, hostdomain.AgencyStatusActive)
	agency, err := scanAgency(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM agencies %s`, agencyColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.Agency{}, false, nil
	}
	if err != nil {
		return hostdomain.Agency{}, false, err
	}
	return agency, true, nil
}

func queryAgencyByOwnerMaybe(ctx context.Context, q sqlQueryer, ownerUserID int64, lock bool) (hostdomain.Agency, bool, error) {
	clause := "WHERE owner_user_id = ?"
	if lock {
		// 后台创建 Agency 时要锁住 owner 名下所有历史 Agency 行，避免 active/closed 切换和新建并发。
		clause += " FOR UPDATE"
	}
	clause, args := appScopedClause(ctx, clause, ownerUserID)
	agency, err := scanAgency(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM agencies %s`, agencyColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.Agency{}, false, nil
	}
	if err != nil {
		return hostdomain.Agency{}, false, err
	}
	return agency, true, nil
}

func scanAgency(scanner rowScanner) (hostdomain.Agency, error) {
	var agency hostdomain.Agency
	err := scanner.Scan(
		&agency.AgencyID,
		&agency.OwnerUserID,
		&agency.RegionID,
		&agency.ParentBDUserID,
		&agency.Name,
		&agency.Status,
		&agency.JoinEnabled,
		&agency.MaxHosts,
		&agency.CreatedByUserID,
		&agency.CreatedAtMs,
		&agency.UpdatedAtMs,
	)
	return agency, err
}

func queryBDProfile(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.BDProfile, error) {
	clause, args = appScopedClause(ctx, clause, args...)
	profile, err := scanBDProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM bd_profiles %s`, bdProfileColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.BDProfile{}, xerr.New(xerr.NotFound, "bd profile not found")
	}
	return profile, err
}

func queryBDProfileMaybe(ctx context.Context, q sqlQueryer, userID int64, lock bool) (hostdomain.BDProfile, bool, error) {
	clause := "WHERE user_id = ? AND status = ?"
	if lock {
		clause += " FOR UPDATE"
	}
	clause, args := appScopedClause(ctx, clause, userID, hostdomain.BDStatusActive)
	profile, err := scanBDProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM bd_profiles %s`, bdProfileColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.BDProfile{}, false, nil
	}
	if err != nil {
		return hostdomain.BDProfile{}, false, err
	}
	return profile, true, nil
}

func queryBDProfileByUserMaybe(ctx context.Context, q sqlQueryer, userID int64, lock bool) (hostdomain.BDProfile, bool, error) {
	clause := "WHERE user_id = ?"
	if lock {
		// 后台创建/停用角色使用主键锁，覆盖 active 和 disabled 两种状态。
		clause += " FOR UPDATE"
	}
	clause, args := appScopedClause(ctx, clause, userID)
	profile, err := scanBDProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM bd_profiles %s`, bdProfileColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.BDProfile{}, false, nil
	}
	if err != nil {
		return hostdomain.BDProfile{}, false, err
	}
	return profile, true, nil
}

func scanBDProfile(scanner rowScanner) (hostdomain.BDProfile, error) {
	var profile hostdomain.BDProfile
	err := scanner.Scan(
		&profile.UserID,
		&profile.Role,
		&profile.RegionID,
		&profile.ParentLeaderUserID,
		&profile.Status,
		&profile.CreatedByUserID,
		&profile.CreatedAtMs,
		&profile.UpdatedAtMs,
	)
	return profile, err
}

func queryCoinSellerProfile(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.CoinSellerProfile, error) {
	clause, args = appScopedClause(ctx, clause, args...)
	profile, err := scanCoinSellerProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM coin_seller_profiles %s`, coinSellerProfileColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.CoinSellerProfile{}, xerr.New(xerr.NotFound, "coin_seller profile not found")
	}
	return profile, err
}

func queryCoinSellerProfileByUserMaybe(ctx context.Context, q sqlQueryer, userID int64, lock bool) (hostdomain.CoinSellerProfile, bool, error) {
	clause := "WHERE user_id = ?"
	if lock {
		// 币商身份可以和 Agency/BD/BD Leader 并存，但同一用户只能有一条币商身份事实。
		clause += " FOR UPDATE"
	}
	clause, args := appScopedClause(ctx, clause, userID)
	profile, err := scanCoinSellerProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM coin_seller_profiles %s`, coinSellerProfileColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.CoinSellerProfile{}, false, nil
	}
	if err != nil {
		return hostdomain.CoinSellerProfile{}, false, err
	}
	return profile, true, nil
}

func scanCoinSellerProfile(scanner rowScanner) (hostdomain.CoinSellerProfile, error) {
	var profile hostdomain.CoinSellerProfile
	err := scanner.Scan(
		&profile.UserID,
		&profile.Status,
		&profile.MerchantAssetType,
		&profile.CreatedByUserID,
		&profile.CreatedAtMs,
		&profile.UpdatedAtMs,
	)
	return profile, err
}

func queryAgencyMembership(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.AgencyMembership, error) {
	clause, args = appScopedClause(ctx, clause, args...)
	membership, err := scanAgencyMembership(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM agency_memberships %s`, agencyMembershipColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.AgencyMembership{}, xerr.New(xerr.NotFound, "agency membership not found")
	}
	return membership, err
}

func queryActiveMembershipByHost(ctx context.Context, q sqlQueryer, hostUserID int64, lock bool) (hostdomain.AgencyMembership, bool, error) {
	clause := "WHERE host_user_id = ? AND status = ?"
	if lock {
		clause += " FOR UPDATE"
	}
	clause, args := appScopedClause(ctx, clause, hostUserID, hostdomain.MembershipStatusActive)
	membership, err := scanAgencyMembership(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM agency_memberships %s`, agencyMembershipColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.AgencyMembership{}, false, nil
	}
	if err != nil {
		return hostdomain.AgencyMembership{}, false, err
	}
	return membership, true, nil
}

func queryAgencyMemberships(ctx context.Context, q sqlQueryer, query string, args ...any) ([]hostdomain.AgencyMembership, error) {
	rows, err := q.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	memberships := make([]hostdomain.AgencyMembership, 0)
	for rows.Next() {
		membership, err := scanAgencyMembership(rows)
		if err != nil {
			return nil, err
		}
		memberships = append(memberships, membership)
	}
	return memberships, rows.Err()
}

func scanAgencyMembership(scanner rowScanner) (hostdomain.AgencyMembership, error) {
	var membership hostdomain.AgencyMembership
	err := scanner.Scan(
		&membership.MembershipID,
		&membership.AgencyID,
		&membership.HostUserID,
		&membership.RegionID,
		&membership.MembershipType,
		&membership.Status,
		&membership.JoinedAtMs,
		&membership.EndedAtMs,
		&membership.EndedByUserID,
		&membership.EndedReason,
		&membership.CreatedAtMs,
		&membership.UpdatedAtMs,
	)
	return membership, err
}

func queryAgencyApplication(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.AgencyApplication, error) {
	clause, args = appScopedClause(ctx, clause, args...)
	application, err := scanAgencyApplication(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM agency_applications %s`, agencyApplicationColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.AgencyApplication{}, xerr.New(xerr.NotFound, "agency application not found")
	}
	return application, err
}

func queryAgencyApplications(ctx context.Context, q sqlQueryer, query string, args ...any) ([]hostdomain.AgencyApplication, error) {
	rows, err := q.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	applications := make([]hostdomain.AgencyApplication, 0)
	for rows.Next() {
		application, err := scanAgencyApplication(rows)
		if err != nil {
			return nil, err
		}
		applications = append(applications, application)
	}
	return applications, rows.Err()
}

func scanAgencyApplication(scanner rowScanner) (hostdomain.AgencyApplication, error) {
	var application hostdomain.AgencyApplication
	err := scanner.Scan(
		&application.ApplicationID,
		&application.CommandID,
		&application.ApplicantUserID,
		&application.AgencyID,
		&application.RegionID,
		&application.Status,
		&application.ReviewedByUserID,
		&application.ReviewReason,
		&application.ReviewedAtMs,
		&application.CreatedAtMs,
		&application.UpdatedAtMs,
	)
	return application, err
}

func queryRoleInvitation(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.RoleInvitation, error) {
	clause, args = appScopedClause(ctx, clause, args...)
	invitation, err := scanRoleInvitation(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM role_invitations %s`, roleInvitationColumns, clause), args...))
	if err == sql.ErrNoRows {
		return hostdomain.RoleInvitation{}, xerr.New(xerr.NotFound, "role invitation not found")
	}
	return invitation, err
}

func scanRoleInvitation(scanner rowScanner) (hostdomain.RoleInvitation, error) {
	var invitation hostdomain.RoleInvitation
	err := scanner.Scan(
		&invitation.InvitationID,
		&invitation.CommandID,
		&invitation.InvitationType,
		&invitation.Status,
		&invitation.InviterUserID,
		&invitation.InviterBDUserID,
		&invitation.TargetUserID,
		&invitation.RegionID,
		&invitation.AgencyName,
		&invitation.ParentBDUserID,
		&invitation.ParentLeaderUserID,
		&invitation.ProcessedByUserID,
		&invitation.ProcessReason,
		&invitation.ProcessedAtMs,
		&invitation.CreatedAtMs,
		&invitation.UpdatedAtMs,
	)
	return invitation, err
}

func reviewResultByApplicationID(ctx context.Context, q sqlQueryer, applicationID int64) (hostdomain.ReviewAgencyApplicationResult, error) {
	application, err := queryAgencyApplication(ctx, q, "WHERE application_id = ?", applicationID)
	if err != nil {
		return hostdomain.ReviewAgencyApplicationResult{}, err
	}
	result := hostdomain.ReviewAgencyApplicationResult{Application: application}
	if application.Status == hostdomain.ApplicationStatusApproved {
		profile, err := queryHostProfile(ctx, q, "WHERE user_id = ?", application.ApplicantUserID)
		if err != nil {
			return hostdomain.ReviewAgencyApplicationResult{}, err
		}
		membership, err := queryAgencyMembership(ctx, q, "WHERE membership_id = ?", profile.CurrentMembershipID)
		if err != nil {
			return hostdomain.ReviewAgencyApplicationResult{}, err
		}
		result.HostProfile = profile
		result.Membership = membership
	}
	return result, nil
}

func kickResultByMembershipID(ctx context.Context, q sqlQueryer, membershipID int64) (hostdomain.KickAgencyHostResult, error) {
	membership, err := queryAgencyMembership(ctx, q, "WHERE membership_id = ?", membershipID)
	if err != nil {
		return hostdomain.KickAgencyHostResult{}, err
	}
	profile, err := queryHostProfile(ctx, q, "WHERE user_id = ?", membership.HostUserID)
	if err != nil {
		return hostdomain.KickAgencyHostResult{}, err
	}
	return hostdomain.KickAgencyHostResult{Membership: membership, HostProfile: profile}, nil
}

func processResultByInvitationID(ctx context.Context, q sqlQueryer, invitationID int64) (hostdomain.ProcessRoleInvitationResult, error) {
	invitation, err := queryRoleInvitation(ctx, q, "WHERE invitation_id = ?", invitationID)
	if err != nil {
		return hostdomain.ProcessRoleInvitationResult{}, err
	}
	result := hostdomain.ProcessRoleInvitationResult{Invitation: invitation}
	if invitation.Status != hostdomain.InvitationStatusAccepted {
		return result, nil
	}
	if invitation.InvitationType == hostdomain.InvitationTypeAgency {
		if profile, err := queryHostProfile(ctx, q, "WHERE user_id = ?", invitation.TargetUserID); err == nil {
			result.HostProfile = profile
			if profile.CurrentMembershipID > 0 {
				result.Membership, _ = queryAgencyMembership(ctx, q, "WHERE membership_id = ?", profile.CurrentMembershipID)
			}
		}
		if agency, ok, err := queryActiveAgencyByOwner(ctx, q, invitation.TargetUserID, false); err != nil {
			return hostdomain.ProcessRoleInvitationResult{}, err
		} else if ok {
			result.Agency = agency
		}
	} else if invitation.InvitationType == hostdomain.InvitationTypeBD {
		if bd, err := queryBDProfile(ctx, q, "WHERE user_id = ?", invitation.TargetUserID); err == nil {
			result.BDProfile = bd
		}
	}
	return result, nil
}
