// services/IdentityService.ts
// 统一身份识别服务（内存索引），用于 /api/ingest 流程中匹配或创建用户。
// 与 v1.4 文档的统一用户结构保持一致（source_profiles / ai_insights / crm_info）[^5]

export interface IdentityMatch {
  userId: string
  confidence: number
  reasons: string[]
}

type IndexMaps = {
  emailToUser: Map<string, string>
  phoneToUser: Map<string, string>
  usernameToUser: Map<string, string>
  userStore: Map<string, Record<string, any>>
}

export class IdentityService {
  private static instance: IdentityService
  private index: IndexMaps

  private constructor() {
    this.index = {
      emailToUser: new Map(),
      phoneToUser: new Map(),
      usernameToUser: new Map(),
      userStore: new Map(),
    }
  }

  public static getInstance(): IdentityService {
    if (!IdentityService.instance) {
      IdentityService.instance = new IdentityService()
    }
    return IdentityService.instance
  }

  // 基于映射数据寻找可能的用户匹配
  public async findMatchingIdentity(mappedData: Record<string, any>): Promise<IdentityMatch[]> {
    const matches: IdentityMatch[] = []
    const seen = new Set<string>()

    const tryAdd = (userId: string | undefined, confidence: number, reason: string) => {
      if (!userId) return
      if (seen.has(userId)) return
      seen.add(userId)
      matches.push({ userId, confidence, reasons: [reason] })
    }

    if (mappedData.email) {
      tryAdd(this.index.emailToUser.get(String(mappedData.email).toLowerCase()), 0.95, "email")
    }
    if (mappedData.phone) {
      tryAdd(this.index.phoneToUser.get(String(mappedData.phone)), 0.92, "phone")
    }
    if (mappedData.username) {
      tryAdd(this.index.usernameToUser.get(String(mappedData.username).toLowerCase()), 0.7, "username")
    }

    // 简单加权：若同一userId命中多个关键字段，提升置信度
    const aggregated = new Map<string, IdentityMatch>()
    for (const m of matches) {
      const exists = aggregated.get(m.userId)
      if (!exists) {
        aggregated.set(m.userId, { ...m })
      } else {
        exists.confidence = Math.min(0.99, exists.confidence + 0.05)
        exists.reasons = Array.from(new Set([...exists.reasons, ...m.reasons]))
      }
    }

    return Array.from(aggregated.values()).sort((a, b) => b.confidence - a.confidence)
  }

  // 创建新身份
  public async createNewIdentity(mappedData: Record<string, any>): Promise<string> {
    const base =
      (mappedData.phone && `phone_${mappedData.phone}`) ||
      (mappedData.email && `email_${String(mappedData.email).toLowerCase()}`) ||
      (mappedData.username && `uname_${String(mappedData.username).toLowerCase()}`) ||
      `anon_${Date.now()}`

    const userId = `user_${this.shortHash(base)}`
    this.index.userStore.set(userId, { userId, ...mappedData })
    this.bindIndexes(userId, mappedData)
    return userId
  }

  // 更新身份（同步索引）
  public async updateIdentity(userId: string, mappedData: Record<string, any>): Promise<void> {
    const cur = this.index.userStore.get(userId) || { userId }
    const updated = { ...cur, ...mappedData }
    this.index.userStore.set(userId, updated)
    this.bindIndexes(userId, mappedData)
  }

  private bindIndexes(userId: string, mappedData: Record<string, any>) {
    if (mappedData.email) {
      this.index.emailToUser.set(String(mappedData.email).toLowerCase(), userId)
    }
    if (mappedData.phone) {
      this.index.phoneToUser.set(String(mappedData.phone), userId)
    }
    if (mappedData.username) {
      this.index.usernameToUser.set(String(mappedData.username).toLowerCase(), userId)
    }
  }

  private shortHash(str: string): string {
    // 简单、稳定的字符串哈希（djb2 变体），避免依赖
    let h = 5381
    for (let i = 0; i < str.length; i++) {
      h = (h * 33) ^ str.charCodeAt(i)
    }
    // 转为正数并截断
    return (h >>> 0).toString(36)
  }
}
