import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { NextFunction, Request, Response } from 'express'

vi.mock('../../lib/prisma', () => ({
  prisma: {
    subscription: {
      findUnique: vi.fn(),
    },
  },
}))

import { prisma } from '../../lib/prisma'
import { requireActiveSubscription, requireFullAccess } from './subscription.entitlement'

function createRes() {
  const res = {
    status: vi.fn().mockReturnThis(),
    json: vi.fn().mockReturnThis(),
  }
  return res as unknown as Response & { status: ReturnType<typeof vi.fn>; json: ReturnType<typeof vi.fn> }
}

describe('subscription.entitlement middleware', () => {
  beforeEach(() => vi.clearAllMocks())

  it('rejects unauthenticated requests before touching subscription storage', async () => {
    const req = {} as Request
    const res = createRes()
    const next = vi.fn() as NextFunction

    await requireActiveSubscription(req, res, next)

    expect(res.status).toHaveBeenCalledWith(401)
    expect(res.json).toHaveBeenCalledWith({ error: 'unauthenticated' })
    expect(prisma.subscription.findUnique).not.toHaveBeenCalled()
    expect(next).not.toHaveBeenCalled()
  })

  it('rejects missing or expired subscriptions with a precise entitlement payload', async () => {
    vi.mocked(prisma.subscription.findUnique).mockResolvedValue(null as never)
    const req = { companyId: 'company_1' } as Request
    const res = createRes()
    const next = vi.fn() as NextFunction

    await requireActiveSubscription(req, res, next)

    expect(prisma.subscription.findUnique).toHaveBeenCalledWith({ where: { companyId: 'company_1' } })
    expect(res.status).toHaveBeenCalledWith(403)
    expect(res.json).toHaveBeenCalledWith(expect.objectContaining({
      error: 'subscription_required',
      subscriptionStatus: 'EXPIRED',
      accessLevel: 'none',
    }))
    expect(next).not.toHaveBeenCalled()
  })

  it('allows limited subscriptions through requireActiveSubscription but annotates the request', async () => {
    vi.mocked(prisma.subscription.findUnique).mockResolvedValue({ status: 'PAST_DUE' } as never)
    const req = { companyId: 'company_1' } as Request & { subscriptionStatus?: string; accessLevel?: string }
    const res = createRes()
    const next = vi.fn() as NextFunction

    await requireActiveSubscription(req, res, next)

    expect(req.subscriptionStatus).toBe('PAST_DUE')
    expect(req.accessLevel).toBe('limited')
    expect(next).toHaveBeenCalledOnce()
    expect(res.status).not.toHaveBeenCalled()
  })

  it('requires full access for write-protected actions', async () => {
    vi.mocked(prisma.subscription.findUnique).mockResolvedValue({ status: 'SUSPENDED' } as never)
    const req = { companyId: 'company_1' } as Request
    const res = createRes()
    const next = vi.fn() as NextFunction

    await requireFullAccess(req, res, next)

    expect(res.status).toHaveBeenCalledWith(403)
    expect(res.json).toHaveBeenCalledWith(expect.objectContaining({
      error: 'insufficient_access',
      subscriptionStatus: 'SUSPENDED',
      accessLevel: 'read_only',
    }))
    expect(next).not.toHaveBeenCalled()
  })

  it('passes active subscriptions through requireFullAccess', async () => {
    vi.mocked(prisma.subscription.findUnique).mockResolvedValue({ status: 'ACTIVE' } as never)
    const req = { companyId: 'company_1' } as Request & { subscriptionStatus?: string; accessLevel?: string }
    const res = createRes()
    const next = vi.fn() as NextFunction

    await requireFullAccess(req, res, next)

    expect(req.subscriptionStatus).toBe('ACTIVE')
    expect(req.accessLevel).toBe('full')
    expect(next).toHaveBeenCalledOnce()
    expect(res.status).not.toHaveBeenCalled()
  })
})
