import { describe, expect, test } from 'vitest'
import { OverlayAction } from 'apps/companion/main/automation/application/ports/IOverlaySyncPort'
import { IAutomationLifecycleEmitter, LifecycleCallback } from '@core/automation/infrastructure//IAutomationLifecycleEmitter'
import { OverlaySyncService } from 'apps/companion/main/automation/application/services/OverlaySyncService'

class MockLifecycleEmitter implements IAutomationLifecycleEmitter {
  private callbacks: Set<LifecycleCallback> = new Set()
  onLifecycle(cb: LifecycleCallback): void {
    this.callbacks.add(cb)
  }
  offLifecycle(cb: LifecycleCallback): void {
    this.callbacks.delete(cb)
  }
  async emit(event: AutomationEvent) {
    for (const cb of Array.from(this.callbacks)) {
      // fire without awaiting to simulate async emitter
      cb(event)
    }
  }
}

describe('OverlaySyncService (unit)', () => {
  test('startAction resolves as confirmed only after action-started event is emitted', async () => {
    const emitter = new MockLifecycleEmitter()
    // create service wiring: pass emitter as dependency (constructor shape expected)
    const svc = new OverlaySyncService({
      lifecycleEmitter: emitter,
      logger: console as unknown,
      publisher: { publish: async () => {} },
    })

    const action: OverlayAction = { id: 'add-car', label: 'Adding...' }

    // start the action but don't emit event yet
    const promise = svc.startAction(action)

    // wait a small tick to ensure promise hasn't resolved prematurely
    await new Promise((r) => setTimeout(r, 10))

    let resolved = false
    promise.then(() => (resolved = true))
    expect(resolved).toBe(false)

    // now emit action-started
    await emitter.emit({ type: 'action-started', actionId: 'add-car', timestamp: Date.now() })

    const ack = await promise
    expect(ack.status).toBe('confirmed')
    expect(ack.id).toBe('add-car')
  })
})