import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import {
  IUserQueryRepository,
  UserQueryItem,
  UserQueryFilters,
  UserQueryPagination,
  UserQuerySort,
  UserQueryResult,
} from '../../../domain/repositories/user-query.repository';
import { Prisma } from '@prisma/client';

@Injectable()
export class UserQueryRepositoryImpl implements IUserQueryRepository {
  private readonly logger = new Logger(UserQueryRepositoryImpl.name);

  constructor(private readonly prisma: PrismaService) {}

  async findMany(
    filters: UserQueryFilters,
    pagination: UserQueryPagination,
    sort?: UserQuerySort,
  ): Promise<UserQueryResult> {
    const where = this.buildWhereClause(filters);
    const orderBy = this.buildOrderBy(sort);

    // 认种筛选：UserQueryView.personalAdoptionCount 可能未同步，
    // 改为实时查询 PlantingOrderQueryView（与 getBatchUserStats 数据源一致）
    if (filters.minAdoptions !== undefined || filters.maxAdoptions !== undefined) {
      const adoptedAccounts = await this.prisma.plantingOrderQueryView.groupBy({
        by: ['accountSequence'],
        where: { status: 'MINING_ENABLED' },
        _count: { id: true },
      });
      const adoptedSeqs = new Set(adoptedAccounts.map(a => a.accountSequence));

      if (filters.minAdoptions !== undefined && filters.minAdoptions > 0) {
        // 已认种：accountSequence 必须在有 MINING_ENABLED 订单的集合中
        where.accountSequence = {
          ...(typeof where.accountSequence === 'object' ? where.accountSequence as any : {}),
          in: [...adoptedSeqs],
        };
      }
      if (filters.maxAdoptions !== undefined && filters.maxAdoptions === 0) {
        // 未认种：accountSequence 不在有 MINING_ENABLED 订单的集合中
        where.accountSequence = {
          ...(typeof where.accountSequence === 'object' ? where.accountSequence as any : {}),
          notIn: [...adoptedSeqs],
        };
      }
    }

    const [items, total] = await Promise.all([
      this.prisma.userQueryView.findMany({
        where,
        orderBy,
        skip: (pagination.page - 1) * pagination.pageSize,
        take: pagination.pageSize,
      }),
      this.prisma.userQueryView.count({ where }),
    ]);

    return {
      items: items.map(this.mapToQueryItem),
      total,
      page: pagination.page,
      pageSize: pagination.pageSize,
      totalPages: Math.ceil(total / pagination.pageSize),
    };
  }

  async findById(userId: bigint): Promise<UserQueryItem | null> {
    const item = await this.prisma.userQueryView.findUnique({
      where: { userId },
    });

    return item ? this.mapToQueryItem(item) : null;
  }

  async findByAccountSequence(accountSequence: string): Promise<UserQueryItem | null> {
    const item = await this.prisma.userQueryView.findUnique({
      where: { accountSequence },
    });

    return item ? this.mapToQueryItem(item) : null;
  }

  async upsert(data: {
    userId: bigint;
    accountSequence: string;
    nickname?: string | null;
    avatarUrl?: string | null;
    phoneNumberMasked?: string | null;
    inviterSequence?: string | null;
    kycStatus?: string;
    status?: string;
    registeredAt: Date;
  }): Promise<void> {
    // 使用 accountSequence 作为唯一键进行 upsert
    // 这样可以正确处理 userId 不一致的情况（旧系统可能写入 userId=0）
    await this.prisma.userQueryView.upsert({
      where: { accountSequence: data.accountSequence },
      create: {
        userId: data.userId,
        accountSequence: data.accountSequence,
        nickname: data.nickname ?? null,
        avatarUrl: data.avatarUrl ?? null,
        phoneNumberMasked: data.phoneNumberMasked ?? null,
        inviterSequence: data.inviterSequence ?? null,
        kycStatus: data.kycStatus ?? 'NOT_VERIFIED',
        status: data.status ?? 'ACTIVE',
        registeredAt: data.registeredAt,
        syncedAt: new Date(),
      },
      update: {
        // 始终更新 userId 以修复旧数据
        userId: data.userId,
        nickname: data.nickname !== undefined ? data.nickname : undefined,
        avatarUrl: data.avatarUrl !== undefined ? data.avatarUrl : undefined,
        phoneNumberMasked: data.phoneNumberMasked !== undefined ? data.phoneNumberMasked : undefined,
        inviterSequence: data.inviterSequence !== undefined ? data.inviterSequence : undefined,
        kycStatus: data.kycStatus !== undefined ? data.kycStatus : undefined,
        status: data.status !== undefined ? data.status : undefined,
        syncedAt: new Date(),
      },
    });

    this.logger.debug(`[UserQueryView] Upserted user ${data.accountSequence}`);
  }

  async updateProfile(
    userId: bigint,
    data: {
      nickname?: string | null;
      avatarUrl?: string | null;
    },
  ): Promise<void> {
    await this.prisma.userQueryView.update({
      where: { userId },
      data: {
        ...data,
        syncedAt: new Date(),
      },
    });

    this.logger.debug(`[UserQueryView] Updated profile for user ${userId}`);
  }

  async updateAdoptionStats(
    userId: bigint,
    data: {
      personalAdoptionCount?: number;
      teamAddressCount?: number;
      teamAdoptionCount?: number;
    },
  ): Promise<void> {
    await this.prisma.userQueryView.update({
      where: { userId },
      data: {
        ...data,
        syncedAt: new Date(),
      },
    });

    this.logger.debug(`[UserQueryView] Updated adoption stats for user ${userId}`);
  }

  async updateAuthorizationStats(
    userId: bigint,
    data: {
      provinceAdoptionCount?: number;
      cityAdoptionCount?: number;
    },
  ): Promise<void> {
    await this.prisma.userQueryView.update({
      where: { userId },
      data: {
        ...data,
        syncedAt: new Date(),
      },
    });

    this.logger.debug(`[UserQueryView] Updated authorization stats for user ${userId}`);
  }

  async updateStatus(userId: bigint, status: string): Promise<void> {
    await this.prisma.userQueryView.update({
      where: { userId },
      data: {
        status,
        syncedAt: new Date(),
      },
    });

    this.logger.debug(`[UserQueryView] Updated status for user ${userId} to ${status}`);
  }

  async updateKycStatus(userId: bigint, kycStatus: string): Promise<void> {
    await this.prisma.userQueryView.update({
      where: { userId },
      data: {
        kycStatus,
        syncedAt: new Date(),
      },
    });

    this.logger.debug(`[UserQueryView] Updated KYC status for user ${userId} to ${kycStatus}`);
  }

  async updateKycStatusByAccountSequence(accountSequence: string, kycStatus: string): Promise<void> {
    await this.prisma.userQueryView.update({
      where: { accountSequence },
      data: {
        kycStatus,
        syncedAt: new Date(),
      },
    });

    this.logger.debug(`[UserQueryView] Updated KYC status for user ${accountSequence} to ${kycStatus}`);
  }

  async updateOnlineStatus(userId: bigint, isOnline: boolean): Promise<void> {
    await this.prisma.userQueryView.update({
      where: { userId },
      data: {
        isOnline,
        lastActiveAt: isOnline ? new Date() : undefined,
        syncedAt: new Date(),
      },
    });
  }

  async batchUpdateOnlineStatus(userIds: bigint[], isOnline: boolean): Promise<void> {
    await this.prisma.userQueryView.updateMany({
      where: { userId: { in: userIds } },
      data: {
        isOnline,
        lastActiveAt: isOnline ? new Date() : undefined,
        syncedAt: new Date(),
      },
    });

    this.logger.debug(`[UserQueryView] Batch updated online status for ${userIds.length} users`);
  }

  async count(filters?: UserQueryFilters): Promise<number> {
    const where = filters ? this.buildWhereClause(filters) : {};
    return this.prisma.userQueryView.count({ where });
  }

  async exists(userId: bigint): Promise<boolean> {
    const count = await this.prisma.userQueryView.count({
      where: { userId },
    });
    return count > 0;
  }

  async existsByAccountSequence(accountSequence: string): Promise<boolean> {
    const count = await this.prisma.userQueryView.count({
      where: { accountSequence },
    });
    return count > 0;
  }

  // ==================== Private Methods ====================

  private buildWhereClause(filters: UserQueryFilters): Prisma.UserQueryViewWhereInput {
    const where: Prisma.UserQueryViewWhereInput = {};

    // 关键词搜索 (账号序列号/昵称)
    if (filters.keyword) {
      where.OR = [
        { accountSequence: { contains: filters.keyword, mode: 'insensitive' } },
        { nickname: { contains: filters.keyword, mode: 'insensitive' } },
      ];
    }

    // 状态筛选
    if (filters.status) {
      where.status = filters.status;
    }

    // KYC状态筛选
    if (filters.kycStatus) {
      where.kycStatus = filters.kycStatus;
    }

    // 是否有推荐人
    if (filters.hasInviter !== undefined) {
      where.inviterSequence = filters.hasInviter ? { not: null } : null;
    }

    // 认种数范围：不再使用 personalAdoptionCount（预计算字段可能未同步），
    // 改为在 findMany 中实时查询 PlantingOrderQueryView 处理

    // 注册时间范围
    if (filters.registeredAfter || filters.registeredBefore) {
      where.registeredAt = {};
      if (filters.registeredAfter) {
        where.registeredAt.gte = filters.registeredAfter;
      }
      if (filters.registeredBefore) {
        where.registeredAt.lte = filters.registeredBefore;
      }
    }

    return where;
  }

  private buildOrderBy(sort?: UserQuerySort): Prisma.UserQueryViewOrderByWithRelationInput {
    if (!sort) {
      return { registeredAt: 'desc' };
    }

    return { [sort.field]: sort.order };
  }

  private mapToQueryItem(item: {
    userId: bigint;
    accountSequence: string;
    nickname: string | null;
    avatarUrl: string | null;
    phoneNumberMasked: string | null;
    inviterSequence: string | null;
    kycStatus: string;
    personalAdoptionCount: number;
    teamAddressCount: number;
    teamAdoptionCount: number;
    provinceAdoptionCount: number;
    cityAdoptionCount: number;
    leaderboardRank: number | null;
    status: string;
    isOnline: boolean;
    registeredAt: Date;
    lastActiveAt: Date | null;
  }): UserQueryItem {
    return {
      userId: item.userId,
      accountSequence: item.accountSequence,
      nickname: item.nickname,
      avatarUrl: item.avatarUrl,
      phoneNumberMasked: item.phoneNumberMasked,
      inviterSequence: item.inviterSequence,
      kycStatus: item.kycStatus,
      personalAdoptionCount: item.personalAdoptionCount,
      teamAddressCount: item.teamAddressCount,
      teamAdoptionCount: item.teamAdoptionCount,
      provinceAdoptionCount: item.provinceAdoptionCount,
      cityAdoptionCount: item.cityAdoptionCount,
      leaderboardRank: item.leaderboardRank,
      status: item.status,
      isOnline: item.isOnline,
      registeredAt: item.registeredAt,
      lastActiveAt: item.lastActiveAt,
    };
  }
}
