import { describe, it, expect } from 'vitest'
import { stampLifecycleOnTransition, TaskSchema, type Task } from '../tasks.js'

function makeTask(overrides: Partial<Task> = {}): Task {
  return {
    id: '1',
    subject: 'test task',
    description: 'test description',
    status: 'pending',
    blocks: [],
    blockedBy: [],
    ...overrides,
  }
}

describe('TaskSchema with lifecycle fields', () => {
  it('accepts tasks with no lifecycle fields (backward-compatible)', () => {
    const raw = {
      id: '1',
      subject: 's',
      description: 'd',
      status: 'pending',
      blocks: [],
      blockedBy: [],
    }
    expect(TaskSchema().safeParse(raw).success).toBe(true)
  })

  it('accepts createdAt / startedAt / completedAt / outcome', () => {
    const raw = {
      id: '1',
      subject: 's',
      description: 'd',
      status: 'completed',
      blocks: [],
      blockedBy: [],
      createdAt: 1700000000000,
      startedAt: 1700000001000,
      completedAt: 1700000002000,
      outcome: 'success',
    }
    expect(TaskSchema().safeParse(raw).success).toBe(true)
  })

  it('rejects invalid outcome values', () => {
    const raw = {
      id: '1',
      subject: 's',
      description: 'd',
      status: 'completed',
      blocks: [],
      blockedBy: [],
      outcome: 'wtf',
    }
    expect(TaskSchema().safeParse(raw).success).toBe(false)
  })

  it('accepts all four outcome variants', () => {
    for (const outcome of ['success', 'failure', 'partial', 'cancelled']) {
      const raw = {
        id: '1',
        subject: 's',
        description: 'd',
        status: 'completed',
        blocks: [],
        blockedBy: [],
        outcome,
      }
      expect(TaskSchema().safeParse(raw).success).toBe(true)
    }
  })
})

describe('stampLifecycleOnTransition', () => {
  it('stamps startedAt when transitioning pending → in_progress', () => {
    const existing = makeTask({ status: 'pending' })
    const out = stampLifecycleOnTransition(existing, { status: 'in_progress' })
    expect(typeof out.startedAt).toBe('number')
    expect(out.startedAt).toBeGreaterThan(0)
  })

  it('stamps completedAt when transitioning in_progress → completed', () => {
    const existing = makeTask({ status: 'in_progress', startedAt: 1000 })
    const out = stampLifecycleOnTransition(existing, { status: 'completed' })
    expect(typeof out.completedAt).toBe('number')
    expect(out.completedAt).toBeGreaterThan(0)
  })

  it('does not overwrite an existing startedAt', () => {
    const existing = makeTask({ status: 'pending', startedAt: 1000 })
    const out = stampLifecycleOnTransition(existing, { status: 'in_progress' })
    expect(out.startedAt).toBeUndefined()
  })

  it('does not overwrite an existing completedAt', () => {
    const existing = makeTask({
      status: 'in_progress',
      completedAt: 1000,
    })
    const out = stampLifecycleOnTransition(existing, { status: 'completed' })
    expect(out.completedAt).toBeUndefined()
  })

  it('does not stamp when status is unchanged', () => {
    const existing = makeTask({ status: 'in_progress' })
    const out = stampLifecycleOnTransition(existing, {
      status: 'in_progress',
      description: 'updated',
    })
    expect(out.startedAt).toBeUndefined()
    expect(out.completedAt).toBeUndefined()
  })

  it('does not stamp when status is not in the updates', () => {
    const existing = makeTask({ status: 'pending' })
    const out = stampLifecycleOnTransition(existing, { description: 'new' })
    expect(out.startedAt).toBeUndefined()
    expect(out.completedAt).toBeUndefined()
  })

  it('respects an explicitly-provided startedAt in updates', () => {
    const existing = makeTask({ status: 'pending' })
    const out = stampLifecycleOnTransition(existing, {
      status: 'in_progress',
      startedAt: 42,
    })
    expect(out.startedAt).toBe(42)
  })

  it('preserves other update fields unchanged', () => {
    const existing = makeTask({ status: 'pending' })
    const out = stampLifecycleOnTransition(existing, {
      status: 'in_progress',
      description: 'new desc',
      owner: 'agent-1',
    })
    expect(out.description).toBe('new desc')
    expect(out.owner).toBe('agent-1')
    expect(out.status).toBe('in_progress')
  })
})
