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

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

import { prisma } from '../lib/prisma'
import { requireTenant } from './requireTenant'

function responseStub() {
  const res = { status: vi.fn(), json: vi.fn() }
  res.status.mockReturnValue(res)
  res.json.mockReturnValue(res)
  return res as unknown as Response & typeof res
}

describe('requireTenant middleware', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  it('fails fast when company auth did not set companyId', async () => {
    const req = {} as Request
    const res = responseStub()
    const next = vi.fn() as NextFunction

    await requireTenant(req, res, next)

    expect(res.status).toHaveBeenCalledWith(401)
    expect(res.json).toHaveBeenCalledWith({
      error: 'unauthenticated',
      message: 'Tenant context missing — requireCompanyAuth must run first',
      statusCode: 401,
    })
    expect(prisma.company.findUnique).not.toHaveBeenCalled()
  })

  it('rejects company ids that no longer exist', async () => {
    vi.mocked(prisma.company.findUnique).mockResolvedValue(null)
    const req = { companyId: 'company_missing' } as Request
    const res = responseStub()
    const next = vi.fn() as NextFunction

    await requireTenant(req, res, next)

    expect(prisma.company.findUnique).toHaveBeenCalledWith({ where: { id: 'company_missing' } })
    expect(res.status).toHaveBeenCalledWith(401)
    expect(res.json).toHaveBeenCalledWith({ error: 'company_not_found', message: 'Company not found', statusCode: 401 })
    expect(next).not.toHaveBeenCalled()
  })

  it('attaches the fresh company record and continues', async () => {
    const company = { id: 'company_1', status: 'ACTIVE' }
    vi.mocked(prisma.company.findUnique).mockResolvedValue(company as any)
    const req = { companyId: 'company_1' } as Request
    const res = responseStub()
    const next = vi.fn() as NextFunction

    await requireTenant(req, res, next)

    expect(req.company).toEqual(company)
    expect(next).toHaveBeenCalledTimes(1)
  })
})
