import { Injectable, Logger } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { ConfigService } from '@nestjs/config';
import { firstValueFrom } from 'rxjs';
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';

interface MiningServiceSystemAccount {
  id: string;
  accountType: string;   // OPERATION / PROVINCE / CITY / HEADQUARTERS
  regionCode: string | null;  // 省/市代码，如 440000, 440100
  name: string;
  totalMined: string;
  availableBalance: string;
  totalContribution: string;
  lastSyncedAt: string | null;
}

interface MiningServiceResponse {
  accounts: MiningServiceSystemAccount[];
  total: number;
}

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

  constructor(
    private readonly prisma: PrismaService,
    private readonly httpService: HttpService,
    private readonly configService: ConfigService,
  ) {}

  /**
   * 从 mining-service 获取系统账户挖矿数据
   */
  private async fetchMiningServiceSystemAccounts(): Promise<Map<string, MiningServiceSystemAccount>> {
    const miningServiceUrl = this.configService.get<string>(
      'MINING_SERVICE_URL',
      'http://localhost:3021',
    );

    try {
      const response = await firstValueFrom(
        this.httpService.get<MiningServiceResponse>(
          `${miningServiceUrl}/api/v2/mining/admin/system-accounts`,
        ),
      );

      const miningDataMap = new Map<string, MiningServiceSystemAccount>();
      const body = (response.data as any)?.data ?? response.data;
      for (const account of body.accounts) {
        // 使用 accountType:regionCode 作为 key，与 contribution 表一致
        const key = account.regionCode
          ? `${account.accountType}:${account.regionCode}`
          : account.accountType;
        miningDataMap.set(key, account);
      }

      return miningDataMap;
    } catch (error) {
      this.logger.warn(
        `Failed to fetch mining service system accounts: ${error.message}`,
      );
      return new Map();
    }
  }

  /**
   * 获取系统账户列表
   * 以 synced_system_contributions 为主要数据源，显示所有省市账户
   * 同时关联钱包数据和挖矿数据
   */
  async getSystemAccounts() {
    // 从 CDC 同步的 SyncedSystemContribution 获取算力数据（主要数据源）
    const syncedContributions = await this.prisma.syncedSystemContribution.findMany({
      orderBy: [{ accountType: 'asc' }, { regionCode: 'asc' }],
    });

    // 从 CDC 同步的 SyncedWalletSystemAccount 表获取钱包数据
    const syncedWalletAccounts = await this.prisma.syncedWalletSystemAccount.findMany();

    // 从 mining-service 获取挖矿数据
    const miningDataMap = await this.fetchMiningServiceSystemAccounts();

    // 获取省市名称映射
    const regionNameMap = await this.buildRegionNameMap();

    // 构建钱包数据映射
    const walletMap = new Map<string, any>();
    for (const wallet of syncedWalletAccounts) {
      // 钱包账户的 code 格式为 "CITY-440100"、"PROVINCE-440000" 等
      if (wallet.code) {
        const regionCode = this.extractRegionCodeFromCode(wallet.code);
        if (regionCode) {
          const key = `${wallet.accountType}:${regionCode}`;
          walletMap.set(key, wallet);
        }
      }
      // 同时用 accountType 作为 key（用于 OPERATION、HEADQUARTERS 等）
      walletMap.set(wallet.accountType, wallet);
    }

    // 构建返回数据 - 以算力账户为主
    const accounts = syncedContributions.map((contrib) => {
      const key = contrib.regionCode
        ? `${contrib.accountType}:${contrib.regionCode}`
        : contrib.accountType;

      const wallet = walletMap.get(key) || walletMap.get(contrib.accountType);
      const miningData = miningDataMap.get(key) || miningDataMap.get(contrib.accountType);

      // 获取显示名称
      const displayName = this.getDisplayName(contrib.accountType, contrib.regionCode, regionNameMap);

      return {
        id: contrib.id,
        accountType: contrib.accountType,
        regionCode: contrib.regionCode,
        name: displayName,
        code: wallet?.code || null,
        provinceId: wallet?.provinceId || null,
        cityId: wallet?.cityId || null,
        // 钱包余额（如果有钱包账户）
        shareBalance: wallet?.shareBalance?.toString() || '0',
        usdtBalance: wallet?.usdtBalance?.toString() || '0',
        greenPointBalance: wallet?.greenPointBalance?.toString() || '0',
        frozenShare: wallet?.frozenShare?.toString() || '0',
        frozenUsdt: wallet?.frozenUsdt?.toString() || '0',
        totalInflow: wallet?.totalInflow?.toString() || '0',
        totalOutflow: wallet?.totalOutflow?.toString() || '0',
        blockchainAddress: wallet?.blockchainAddress || null,
        isActive: wallet?.isActive ?? true,
        // 算力数据
        contributionBalance: contrib.contributionBalance?.toString() || '0',
        contributionNeverExpires: contrib.contributionNeverExpires || false,
        // 挖矿数据
        totalMined: miningData?.totalMined || '0',
        availableBalance: miningData?.availableBalance || '0',
        miningContribution: miningData?.totalContribution || '0',
        miningLastSyncedAt: miningData?.lastSyncedAt || null,
        syncedAt: contrib.syncedAt,
        source: 'contribution',
      };
    });

    return {
      accounts,
      total: accounts.length,
    };
  }

  /**
   * 构建区域代码到名称的映射
   */
  private async buildRegionNameMap(): Promise<Map<string, string>> {
    const [provinces, cities] = await Promise.all([
      this.prisma.syncedProvince.findMany({ select: { code: true, name: true } }),
      this.prisma.syncedCity.findMany({ select: { code: true, name: true } }),
    ]);

    const map = new Map<string, string>();
    for (const province of provinces) {
      map.set(province.code, province.name);
    }
    for (const city of cities) {
      map.set(city.code, city.name);
    }
    return map;
  }

  /**
   * 根据账户类型和区域代码获取显示名称
   */
  private getDisplayName(
    accountType: string,
    regionCode: string | null,
    regionNameMap: Map<string, string>,
  ): string {
    // 基础账户类型名称
    const baseNames: Record<string, string> = {
      OPERATION: '运营账户',
      HEADQUARTERS: '总部账户',
      PROVINCE: '省公司账户',
      CITY: '市公司账户',
    };

    if (!regionCode) {
      return baseNames[accountType] || accountType;
    }

    // 根据区域代码查找名称
    const regionName = regionNameMap.get(regionCode);
    if (regionName) {
      if (accountType === 'PROVINCE') {
        return `${regionName}省公司`;
      } else if (accountType === 'CITY') {
        return `${regionName}市公司`;
      }
    }

    // 回退：使用区域代码
    return `${regionCode}账户`;
  }

  /**
   * 从钱包账户的 code 提取区域代码
   * 例如: "CITY-440100" -> "440100", "PROVINCE-440000" -> "440000"
   * 对于非区域账户（如 "HEADQUARTERS"）返回 null
   */
  private extractRegionCodeFromCode(code: string): string | null {
    if (!code) return null;
    // 匹配 CITY-XXXXXX, PROVINCE-XXXXXX, PROV-XXXXXX 格式
    const match = code.match(/^(?:CITY|PROVINCE|PROV)-(\d+)$/);
    return match ? match[1] : null;
  }

  /**
   * 获取系统账户汇总
   */
  async getSystemAccountsSummary() {
    const [
      syncedSystemAccounts,
      syncedPoolAccounts,
      syncedContributions,
      miningConfig,
      circulationPool,
    ] = await Promise.all([
      this.prisma.syncedWalletSystemAccount.findMany(),
      this.prisma.syncedWalletPoolAccount.findMany(),
      this.prisma.syncedSystemContribution.findMany(),
      this.prisma.syncedMiningConfig.findFirst(),
      this.prisma.syncedCirculationPool.findFirst(),
    ]);

    // 从 mining-service 获取挖矿数据汇总
    const miningDataMap = await this.fetchMiningServiceSystemAccounts();

    // 计算总挖矿积分股
    let totalMined = 0;
    for (const miningData of miningDataMap.values()) {
      totalMined += Number(miningData.totalMined || 0);
    }

    // 计算总算力
    let totalSyncedContribution = 0n;
    for (const contrib of syncedContributions) {
      totalSyncedContribution += BigInt(
        contrib.contributionBalance.toString().replace('.', ''),
      );
    }

    return {
      systemAccounts: {
        count: syncedSystemAccounts.length,
        totalBalance: syncedSystemAccounts.reduce(
          (sum, acc) => sum + Number(acc.shareBalance),
          0,
        ).toFixed(8),
        totalMined: totalMined.toFixed(8),
      },
      poolAccounts: {
        count: syncedPoolAccounts.length,
        pools: syncedPoolAccounts.map((pool) => ({
          poolType: pool.poolType,
          name: pool.name,
          balance: pool.balance.toString(),
          targetBurn: pool.targetBurn?.toString(),
          remainingBurn: pool.remainingBurn?.toString(),
        })),
      },
      syncedContributions: {
        count: syncedContributions.length,
        totalBalance: (Number(totalSyncedContribution) / 100000000).toFixed(8),
      },
      miningConfig: miningConfig
        ? {
            totalShares: miningConfig.totalShares.toString(),
            distributionPool: miningConfig.distributionPool.toString(),
            remainingDistribution: miningConfig.remainingDistribution.toString(),
            currentEra: miningConfig.currentEra,
            isActive: miningConfig.isActive,
            activatedAt: miningConfig.activatedAt,
          }
        : null,
      circulationPool: circulationPool
        ? {
            totalShares: circulationPool.totalShares.toString(),
            totalCash: circulationPool.totalCash.toString(),
          }
        : null,
    };
  }

  /**
   * 获取系统账户挖矿记录
   * @param accountType 系统账户类型（OPERATION/PROVINCE/CITY/HEADQUARTERS）
   * @param regionCode 区域代码（省/市代码，如 440000, 440100）
   * @param page 页码
   * @param pageSize 每页数量
   */
  async getSystemAccountMiningRecords(
    accountType: string,
    regionCode: string | null,
    page: number = 1,
    pageSize: number = 20,
  ) {
    const miningServiceUrl = this.configService.get<string>(
      'MINING_SERVICE_URL',
      'http://localhost:3021',
    );

    try {
      const params: Record<string, any> = { page, pageSize };
      if (regionCode) {
        params.regionCode = regionCode;
      }

      const response = await firstValueFrom(
        this.httpService.get(
          `${miningServiceUrl}/api/v2/mining/admin/system-accounts/${accountType}/records`,
          { params },
        ),
      );

      return response.data?.data ?? response.data;
    } catch (error) {
      this.logger.warn(
        `Failed to fetch system account mining records: ${error.message}`,
      );
      return { records: [], total: 0, page, pageSize, accountType, regionCode };
    }
  }

  /**
   * 获取系统账户交易记录
   * @param accountType 系统账户类型（OPERATION/PROVINCE/CITY/HEADQUARTERS）
   * @param regionCode 区域代码（省/市代码，如 440000, 440100）
   * @param page 页码
   * @param pageSize 每页数量
   */
  async getSystemAccountTransactions(
    accountType: string,
    regionCode: string | null,
    page: number = 1,
    pageSize: number = 20,
    referenceType: string | null = null,
  ) {
    const miningServiceUrl = this.configService.get<string>(
      'MINING_SERVICE_URL',
      'http://localhost:3021',
    );

    try {
      const params: Record<string, any> = { page, pageSize };
      if (regionCode) {
        params.regionCode = regionCode;
      }
      if (referenceType) {
        params.referenceType = referenceType;
      }

      const response = await firstValueFrom(
        this.httpService.get(
          `${miningServiceUrl}/api/v2/mining/admin/system-accounts/${accountType}/transactions`,
          { params },
        ),
      );

      return response.data?.data ?? response.data;
    } catch (error) {
      this.logger.warn(
        `Failed to fetch system account transactions: ${error.message}`,
      );
      return { transactions: [], total: 0, page, pageSize, accountType, regionCode };
    }
  }

  /**
   * 获取系统账户算力来源明细
   * 显示该账户的每笔算力来自哪个认种订单
   *
   * @param accountType 系统账户类型（OPERATION/PROVINCE/CITY/HEADQUARTERS）
   * @param regionCode 区域代码（省/市代码，如 440000, 440100）
   * @param page 页码
   * @param pageSize 每页数量
   */
  async getSystemAccountContributionRecords(
    accountType: string,
    regionCode: string | null,
    page: number = 1,
    pageSize: number = 20,
  ) {
    // Prisma 查询 null 值需要用 { equals: null }
    const whereClause = regionCode
      ? { accountType, regionCode }
      : { accountType, regionCode: { equals: null } };

    const [records, total] = await Promise.all([
      this.prisma.syncedSystemContributionRecord.findMany({
        where: whereClause,
        skip: (page - 1) * pageSize,
        take: pageSize,
        orderBy: { createdAt: 'desc' },
      }),
      this.prisma.syncedSystemContributionRecord.count({
        where: whereClause,
      }),
    ]);

    // 获取关联的认种订单和用户信息
    const adoptionIds = [...new Set(records.map(r => r.sourceAdoptionId))];
    const accountSequences = [...new Set(records.map(r => r.sourceAccountSequence))];

    const [adoptions, users] = await Promise.all([
      this.prisma.syncedAdoption.findMany({
        where: { originalAdoptionId: { in: adoptionIds } },
        select: {
          originalAdoptionId: true,
          accountSequence: true,
          treeCount: true,
          adoptionDate: true,
          status: true,
          contributionPerTree: true,
        },
      }),
      this.prisma.syncedUser.findMany({
        where: { accountSequence: { in: accountSequences } },
        select: {
          accountSequence: true,
          phone: true,
          realName: true,
          nickname: true,
        },
      }),
    ]);

    // 构建映射
    const adoptionMap = new Map(adoptions.map(a => [a.originalAdoptionId.toString(), a]));
    const userMap = new Map(users.map(u => [u.accountSequence, u]));

    return {
      records: records.map((record) => {
        const adoption = adoptionMap.get(record.sourceAdoptionId.toString());
        const user = userMap.get(record.sourceAccountSequence);

        return {
          originalRecordId: record.originalRecordId.toString(),
          accountType: record.accountType,
          regionCode: record.regionCode,
          sourceAdoptionId: record.sourceAdoptionId.toString(),
          sourceAccountSequence: record.sourceAccountSequence,
          // 来源类型
          sourceType: record.sourceType,
          levelDepth: record.levelDepth,
          // 认种订单详情
          adoptionTreeCount: adoption?.treeCount || 0,
          adoptionDate: adoption?.adoptionDate || null,
          adoptionStatus: adoption?.status || null,
          contributionPerTree: adoption?.contributionPerTree?.toString() || '0',
          // 用户信息
          sourceUserPhone: user?.phone ? this.maskPhone(user.phone) : null,
          sourceUserName: user?.realName || user?.nickname || null,
          // 分配信息
          distributionRate: record.distributionRate.toString(),
          amount: record.amount.toString(),
          effectiveDate: record.effectiveDate,
          expireDate: record.expireDate,
          isExpired: record.isExpired,
          createdAt: record.createdAt,
          syncedAt: record.syncedAt,
        };
      }),
      total,
      page,
      pageSize,
      totalPages: Math.ceil(total / pageSize),
    };
  }

  /**
   * 手机号脱敏
   */
  private maskPhone(phone: string): string {
    if (!phone || phone.length < 7) return phone;
    return phone.substring(0, 3) + '****' + phone.substring(phone.length - 4);
  }

  /**
   * 获取系统账户算力明细统计
   * 用于显示算力来源的汇总信息
   */
  async getSystemAccountContributionStats(accountType: string, regionCode: string | null) {
    // 获取算力账户信息
    // 使用 findFirst 替代 findUnique，因为 regionCode 可以为 null
    const contribution = await this.prisma.syncedSystemContribution.findFirst({
      where: {
        accountType,
        regionCode: regionCode === null ? { equals: null } : regionCode,
      },
    });

    const whereClause = regionCode
      ? { accountType, regionCode }
      : { accountType, regionCode: { equals: null } };

    // 获取明细记录统计
    const recordStats = await this.prisma.syncedSystemContributionRecord.aggregate({
      where: whereClause,
      _count: true,
      _sum: { amount: true },
    });

    // 获取来源认种订单数量（去重）
    const uniqueAdoptions = await this.prisma.syncedSystemContributionRecord.groupBy({
      by: ['sourceAdoptionId'],
      where: whereClause,
    });

    // 获取来源用户数量（去重）
    const uniqueUsers = await this.prisma.syncedSystemContributionRecord.groupBy({
      by: ['sourceAccountSequence'],
      where: whereClause,
    });

    return {
      accountType,
      regionCode,
      name: contribution?.name || accountType,
      totalContribution: contribution?.contributionBalance?.toString() || '0',
      recordCount: recordStats._count,
      sumFromRecords: recordStats._sum?.amount?.toString() || '0',
      uniqueAdoptionCount: uniqueAdoptions.length,
      uniqueUserCount: uniqueUsers.length,
    };
  }
}
