import { describe, it, expect, beforeEach } from 'vitest'
import {
  saveActiveTimer,
  loadActiveTimer,
  clearActiveTimer,
  restoreElapsedMs,
  type ActiveTimerRecord,
  type PendingStorage,
} from '../active-timer'

function makeStorage(): PendingStorage {
  const map = new Map<string, string>()
  return {
    getItem: (k) => (map.has(k) ? (map.get(k) as string) : null),
    setItem: (k, v) => {
      map.set(k, v)
    },
  }
}

function runningRecord(overrides: Partial<ActiveTimerRecord> = {}): ActiveTimerRecord {
  return {
    timerState: 'running',
    segmentStartEpochMs: 1_700_000_000_000,
    pausedElapsedMs: 0,
    lapStartElapsedMs: 0,
    stepId: 'step-1',
    timeType: 'prozesszeit',
    machinePhase: 'manual1',
    machineStartElapsedMs: 0,
    ...overrides,
  }
}

describe('active-timer store', () => {
  let storage: PendingStorage

  beforeEach(() => {
    storage = makeStorage()
  })

  it('returns null when nothing is stored', () => {
    expect(loadActiveTimer('proj-a', storage)).toBeNull()
  })

  it('saves and loads a running record', () => {
    const rec = runningRecord()
    saveActiveTimer('proj-a', rec, storage)
    const loaded = loadActiveTimer('proj-a', storage)
    expect(loaded).not.toBeNull()
    expect(loaded?.timerState).toBe('running')
    expect(loaded?.segmentStartEpochMs).toBe(1_700_000_000_000)
    expect(loaded?.stepId).toBe('step-1')
  })

  it('saves and loads a paused record', () => {
    const rec = runningRecord({ timerState: 'paused', pausedElapsedMs: 5000 })
    saveActiveTimer('proj-a', rec, storage)
    const loaded = loadActiveTimer('proj-a', storage)
    expect(loaded?.timerState).toBe('paused')
    expect(loaded?.pausedElapsedMs).toBe(5000)
  })

  it('is scoped by projectId — different projects do not interfere', () => {
    saveActiveTimer('proj-a', runningRecord({ stepId: 'step-a' }), storage)
    saveActiveTimer('proj-b', runningRecord({ stepId: 'step-b' }), storage)
    expect(loadActiveTimer('proj-a', storage)?.stepId).toBe('step-a')
    expect(loadActiveTimer('proj-b', storage)?.stepId).toBe('step-b')
  })

  it('clearActiveTimer makes loadActiveTimer return null', () => {
    saveActiveTimer('proj-a', runningRecord(), storage)
    clearActiveTimer('proj-a', storage)
    expect(loadActiveTimer('proj-a', storage)).toBeNull()
  })

  it('survives corrupt JSON without throwing', () => {
    storage.setItem('kadi:active-timer:v1:proj-a', '{not valid json')
    expect(loadActiveTimer('proj-a', storage)).toBeNull()
  })

  it('returns null for unknown timerState values', () => {
    storage.setItem('kadi:active-timer:v1:proj-a', JSON.stringify({ timerState: 'bogus' }))
    expect(loadActiveTimer('proj-a', storage)).toBeNull()
  })

  it('is a no-op when storage is null', () => {
    expect(() => saveActiveTimer('proj-a', runningRecord(), null)).not.toThrow()
    expect(loadActiveTimer('proj-a', null)).toBeNull()
    expect(() => clearActiveTimer('proj-a', null)).not.toThrow()
  })
})

describe('restoreElapsedMs', () => {
  it('running: elapsed = pausedElapsedMs + (now - segmentStart)', () => {
    const rec = runningRecord({
      timerState: 'running',
      segmentStartEpochMs: 1_000_000,
      pausedElapsedMs: 2000,
    })
    // now = segmentStart + 3000 ms
    const elapsed = restoreElapsedMs(rec, 1_003_000)
    expect(elapsed).toBe(5000) // 2000 + 3000
  })

  it('paused: elapsed = pausedElapsedMs only', () => {
    const rec = runningRecord({
      timerState: 'paused',
      segmentStartEpochMs: 1_000_000,
      pausedElapsedMs: 7500,
    })
    const elapsed = restoreElapsedMs(rec, 1_999_999)
    expect(elapsed).toBe(7500)
  })

  it('clamps to zero if clock goes backwards', () => {
    const rec = runningRecord({
      timerState: 'running',
      segmentStartEpochMs: 1_000_000,
      pausedElapsedMs: 0,
    })
    // nowEpochMs < segmentStartEpochMs — clock skew / timezone issue
    const elapsed = restoreElapsedMs(rec, 999_000)
    expect(elapsed).toBe(0)
  })

  it('preserves lapStartElapsedMs after restore for lap computation', () => {
    const rec = runningRecord({
      timerState: 'running',
      segmentStartEpochMs: 1_000_000,
      pausedElapsedMs: 10_000,
      lapStartElapsedMs: 7_000,
    })
    const totalElapsed = restoreElapsedMs(rec, 1_005_000) // 10000 + 5000 = 15000
    const lapElapsed = totalElapsed - rec.lapStartElapsedMs
    expect(lapElapsed).toBe(8000) // 15000 - 7000
  })
})
