import { describe, expect, it, vi } from 'vitest'

vi.mock('../../lib/prisma', () => ({ prisma: {} }))
vi.mock('../../lib/redis', () => ({
  redis: { on: vi.fn(), get: vi.fn(), set: vi.fn(), del: vi.fn(), quit: vi.fn() },
}))

import request from 'supertest'
import { createApp } from '../../app'

const app = createApp()

/** Return today's date as YYYY-MM-DD */
function today(): string {
  return new Date().toISOString().split('T')[0]
}

/** Return a date offset by `days` from today, as YYYY-MM-DD */
function offsetDate(days: number): string {
  const d = new Date()
  d.setDate(d.getDate() + days)
  return d.toISOString().split('T')[0]
}

describe('License Validation API — POST /api/v1/licenses/validate', () => {
  // ─── Success scenarios ──────────────────────────────────────────────

  it('accepts a license expiring in 365 days (valid)', async () => {
    const future = offsetDate(365)
    const res = await request(app)
      .post('/api/v1/licenses/validate')
      .send({ expiration_date: future })

    expect(res.status).toBe(200)
    expect(res.body.data).toMatchObject({
      valid: true,
      message: 'License verified successfully',
    })
    expect(res.body.data.days_remaining).toBeGreaterThanOrEqual(365)
    expect(res.body.data.next_reminder).toBeDefined()
  })

  it('accepts a license expiring in exactly 30 days', async () => {
    const future = offsetDate(30)
    const res = await request(app)
      .post('/api/v1/licenses/validate')
      .send({ expiration_date: future })

    expect(res.status).toBe(200)
    expect(res.body.data.valid).toBe(true)
    expect(res.body.data.days_remaining).toBe(30)
  })

  // ─── Rejection scenarios ────────────────────────────────────────────

  it('rejects a license expiring in 15 days with 422', async () => {
    const nearFuture = offsetDate(15)
    const res = await request(app)
      .post('/api/v1/licenses/validate')
      .send({ expiration_date: nearFuture })

    expect(res.status).toBe(422)
    expect(res.body.error).toBe('LICENSE_EXPIRING_SOON')
    expect(res.body.message).toContain('30 days')
    expect(res.body.details).toBeDefined()
    expect(res.body.details.days_remaining).toBe(15)
    expect(res.body.details.minimum_required).toBe(30)
  })

  it('rejects an expired license with 422', async () => {
    const past = offsetDate(-5)
    const res = await request(app)
      .post('/api/v1/licenses/validate')
      .send({ expiration_date: past })

    expect(res.status).toBe(422)
    expect(res.body.error).toBe('LICENSE_EXPIRED')
    expect(res.body.message).toContain('expired')
  })

  it('rejects an invalid date format with 400', async () => {
    const res = await request(app)
      .post('/api/v1/licenses/validate')
      .send({ expiration_date: 'not-a-date' })

    expect(res.status).toBe(400)
    expect(res.body.error).toBe('LICENSE_INVALID_FORMAT')
    expect(res.body.message).toContain('Unable to parse')
  })

  it('rejects an empty expiration_date with 400', async () => {
    const res = await request(app)
      .post('/api/v1/licenses/validate')
      .send({ expiration_date: '' })

    expect(res.status).toBe(400)
    expect(res.body.error).toBe('validation_error')
  })

  it('rejects a date too far in the future with 400', async () => {
    const res = await request(app)
      .post('/api/v1/licenses/validate')
      .send({ expiration_date: '2055-01-01' })

    expect(res.status).toBe(400)
    expect(res.body.error).toBe('LICENSE_FUTURE_DATE')
  })

  // ─── Multiple date formats ──────────────────────────────────────────

  it('parses MM/DD/YYYY format', async () => {
    const future = new Date()
    future.setFullYear(future.getFullYear() + 1)
    const mm = String(future.getMonth() + 1).padStart(2, '0')
    const dd = String(future.getDate()).padStart(2, '0')
    const yyyy = future.getFullYear()

    const res = await request(app)
      .post('/api/v1/licenses/validate')
      .send({ expiration_date: `${mm}/${dd}/${yyyy}` })

    expect(res.status).toBe(200)
    expect(res.body.data.valid).toBe(true)
  })

  it('parses DD-MMM-YYYY format', async () => {
    const future = new Date()
    future.setFullYear(future.getFullYear() + 1)
    const dd = String(future.getDate()).padStart(2, '0')
    const months = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']
    const mmm = months[future.getMonth()]
    const yyyy = future.getFullYear()

    const res = await request(app)
      .post('/api/v1/licenses/validate')
      .send({ expiration_date: `${dd}-${mmm}-${yyyy}` })

    expect(res.status).toBe(200)
    expect(res.body.data.valid).toBe(true)
  })
})
