import type { Reservation } from '../types'

/** 内存预占：按 storageId 排序加锁，成对失败则全体释放 */
export class ReservationStore {
  private rows = new Map<string, Reservation>()

  list(): Reservation[] {
    return [...this.rows.values()]
  }

  isReserved(storageId: string): boolean {
    return this.rows.has(storageId)
  }

  reservedIds(): Set<string> {
    return new Set(this.rows.keys())
  }

  /** 成对预占：任一失败则回滚已占 */
  tryReservePair(instanceId: string, sourceId: string, targetId: string): {
    ok: boolean
    reason?: 'conflict' | 'same_slot'
    heldThenReleased?: string[]
  } {
    if (sourceId === targetId) return { ok: false, reason: 'same_slot' }
    const ordered = [sourceId, targetId].sort((a, b) => a.localeCompare(b))
    const held: string[] = []
    const now = new Date().toISOString()
    for (const id of ordered) {
      if (this.rows.has(id)) {
        for (const h of held) this.rows.delete(h)
        return { ok: false, reason: 'conflict', heldThenReleased: held }
      }
      this.rows.set(id, { storageId: id, instanceId, status: 'Held', createdAt: now })
      held.push(id)
    }
    for (const id of held) {
      const r = this.rows.get(id)!
      r.status = 'Committed'
    }
    return { ok: true }
  }

  releaseByInstance(instanceId: string): string[] {
    const released: string[] = []
    for (const [id, r] of this.rows) {
      if (r.instanceId === instanceId) {
        this.rows.delete(id)
        released.push(id)
      }
    }
    return released
  }

  /** 演示：手动占住库位（无实例） */
  forceHold(storageId: string, tag = 'manual'): boolean {
    if (this.rows.has(storageId)) return false
    this.rows.set(storageId, {
      storageId,
      instanceId: `force:${tag}`,
      status: 'Committed',
      createdAt: new Date().toISOString()
    })
    return true
  }

  releaseForce(storageId: string) {
    const r = this.rows.get(storageId)
    if (r?.instanceId.startsWith('force:')) this.rows.delete(storageId)
  }

  clear() {
    this.rows.clear()
  }
}
