import { BadRequestException, Injectable } from '@nestjs/common';
import { PlayerAssets, PlayerAssetType } from './player_assets.entity';

@Injectable()
export class PlayerAssetsMemoryService {
  private assets: Map<bigint, PlayerAssets> = new Map();
  private userAssetIndex: Map<string, bigint> = new Map();
  private currentId: bigint = BigInt(1);

  async grantAsset(userId: bigint, assetType: PlayerAssetType, assetId: string, source = 'system', metadata?: Record<string, unknown>): Promise<PlayerAssets> {
    const normalizedAssetId = this.normalizeAssetId(assetId);
    const key = this.indexKey(userId, assetType, normalizedAssetId);
    const existingId = this.userAssetIndex.get(key);
    if (existingId) {
      return this.assets.get(existingId) as PlayerAssets;
    }

    const row = new PlayerAssets();
    row.id = this.currentId++;
    row.user_id = userId;
    row.asset_type = assetType;
    row.asset_id = normalizedAssetId;
    row.source = source || 'system';
    row.metadata = metadata ?? null;
    row.acquired_at = new Date();
    this.assets.set(row.id, row);
    this.userAssetIndex.set(key, row.id);
    return row;
  }

  async hasAsset(userId: bigint, assetType: PlayerAssetType, assetId: string): Promise<boolean> {
    const normalizedAssetId = (assetId || '').trim();
    return normalizedAssetId ? this.userAssetIndex.has(this.indexKey(userId, assetType, normalizedAssetId)) : false;
  }

  async listAssets(userId: bigint, assetType?: PlayerAssetType): Promise<PlayerAssets[]> {
    return Array.from(this.assets.values())
      .filter((row) => row.user_id === userId && (!assetType || row.asset_type === assetType))
      .sort((a, b) => {
        const acquiredDiff = a.acquired_at.getTime() - b.acquired_at.getTime();
        return acquiredDiff !== 0 ? acquiredDiff : Number(a.id - b.id);
      });
  }

  async listAssetIds(userId: bigint, assetType: PlayerAssetType): Promise<string[]> {
    const rows = await this.listAssets(userId, assetType);
    return rows.map((row) => row.asset_id);
  }

  async hasAssetFromSource(userId: bigint, assetType: PlayerAssetType, source: string): Promise<boolean> {
    const normalizedSource = (source || '').trim();
    if (!normalizedSource) {
      return false;
    }
    return Array.from(this.assets.values()).some((row) => (
      row.user_id === userId &&
      row.asset_type === assetType &&
      row.source === normalizedSource
    ));
  }

  private indexKey(userId: bigint, assetType: PlayerAssetType, assetId: string): string {
    return `${userId.toString()}:${assetType}:${assetId}`;
  }

  private normalizeAssetId(assetId: string): string {
    const normalized = (assetId || '').trim();
    if (!/^[A-Za-z0-9_:-]{1,100}$/.test(normalized)) {
      throw new BadRequestException('资产ID格式不正确');
    }
    return normalized;
  }
}
