import fs from 'fs'
import path from 'path'
import { SessionEntry, SessionMap } from '../types'

export class SessionStore {
  private static instance: SessionStore | undefined

  private map: Map<string, SessionEntry> = new Map()
  private sessionsPath: string
  private writeLock: Promise<void> = Promise.resolve()

  private constructor(sessionsPath: string) {
    this.sessionsPath = sessionsPath
    this.load()
  }

  static getInstance(sessionsPath: string): SessionStore {
    if (!SessionStore.instance) {
      SessionStore.instance = new SessionStore(sessionsPath)
    }
    return SessionStore.instance
  }

  load(): void {
    if (!fs.existsSync(this.sessionsPath)) {
      this.map = new Map()
      return
    }
    try {
      const raw = fs.readFileSync(this.sessionsPath, 'utf-8')
      const parsed: SessionMap = JSON.parse(raw)
      this.map = new Map(Object.entries(parsed))
    } catch {
      this.map = new Map()
    }
  }

  get(cardId: string): SessionEntry | undefined {
    return this.map.get(cardId)
  }

  set(cardId: string, entry: SessionEntry): void {
    this.map.set(cardId, entry)
    this.persist()
  }

  remove(cardId: string): void {
    this.map.delete(cardId)
    this.persist()
  }

  getAll(): SessionMap {
    return Object.fromEntries(this.map)
  }

  findByChannelId(channelId: string): SessionEntry | undefined {
    for (const entry of this.map.values()) {
      if (entry.slack_channel_id === channelId) {
        return entry
      }
    }
    return undefined
  }

  private persist(): void {
    this.writeLock = this.writeLock.then(() => this.write())
  }

  private async write(): Promise<void> {
    const dir = path.dirname(this.sessionsPath)
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true })
    }
    const data = JSON.stringify(this.getAll(), null, 2)
    fs.writeFileSync(this.sessionsPath, data, 'utf-8')
  }
}
