import { beforeEach, 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() },
}))
vi.mock('../../middleware/requireCompanyAuth', () => ({
  requireCompanyAuth: (req: any, _res: any, next: any) => {
    req.employee = { id: 'employee_1', firstName: 'Aya', lastName: 'Manager', role: 'MANAGER' }
    next()
  },
  requireCompanyDocumentAuth: (req: any, _res: any, next: any) => {
    req.employee = { id: 'employee_1', firstName: 'Aya', lastName: 'Manager', role: 'MANAGER' }
    next()
  },
}))
vi.mock('../../middleware/requireTenant', () => ({
  requireTenant: (req: any, _res: any, next: any) => {
    req.companyId = 'company_1'
    next()
  },
}))
vi.mock('../../middleware/requireSubscription', () => ({ requireSubscription: (_req: any, _res: any, next: any) => next() }))
vi.mock('../../middleware/requireRole', () => ({ requireRole: () => (_req: any, _res: any, next: any) => next() }))
vi.mock('../../middleware/requireRenterAuth', () => ({
  requireRenterAuth: (req: any, _res: any, next: any) => {
    req.renterId = 'renter_1'
    next()
  },
  optionalRenterAuth: (_req: any, _res: any, next: any) => next(),
}))
vi.mock('../../modules/customers/customer.service', () => ({
  listCustomers: vi.fn(),
  createCustomer: vi.fn(),
  getCustomer: vi.fn(),
  updateCustomer: vi.fn(),
  flagCustomer: vi.fn(),
  unflagCustomer: vi.fn(),
  validateCustomerLicense: vi.fn(),
  uploadLicenseImage: vi.fn(),
  approveLicense: vi.fn(),
  getLicenseImageFile: vi.fn(),
}))
vi.mock('../../modules/notifications/notification.service', () => ({
  listCompany: vi.fn(),
  countUnread: vi.fn(),
  markRead: vi.fn(),
  markAllRead: vi.fn(),
  getPreferences: vi.fn(),
  setPreferences: vi.fn(),
  listCompanyHistory: vi.fn(),
  listRenter: vi.fn(),
  markRenterRead: vi.fn(),
  markAllRenterRead: vi.fn(),
  getRenterPreferences: vi.fn(),
  setRenterPreferences: vi.fn(),
}))
vi.mock('../../modules/analytics/analytics.service', () => ({
  getSummary: vi.fn(),
  getDashboard: vi.fn(),
  getSources: vi.fn(),
  getReport: vi.fn(),
}))

import request from 'supertest'
import { createApp } from '../../app'
import * as customerService from '../../modules/customers/customer.service'
import * as notificationService from '../../modules/notifications/notification.service'
import * as analyticsService from '../../modules/analytics/analytics.service'

const app = createApp()

describe('customer, notification and analytics API validation contracts', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    vi.mocked(customerService.listCustomers).mockResolvedValue({ items: [], page: 2, pageSize: 10, total: 0 } as never)
    vi.mocked(customerService.createCustomer).mockResolvedValue({ id: 'customer_1' } as never)
    vi.mocked(customerService.approveLicense).mockResolvedValue({ id: 'customer_1', licenseStatus: 'APPROVED' } as never)
    vi.mocked(notificationService.listCompanyHistory).mockResolvedValue([] as never)
    vi.mocked(analyticsService.getSummary).mockResolvedValue({ reservations: 0 } as never)
  })

  it('coerces customer list pagination before calling the service', async () => {
    const res = await request(app).get('/api/v1/customers?page=2&pageSize=10&flagged=false&q=Aya')

    expect(res.status).toBe(200)
    expect(customerService.listCustomers).toHaveBeenCalledWith('company_1', {
      page: 2,
      pageSize: 10,
      flagged: 'false',
      q: 'Aya',
    })
  })

  it('rejects malformed customer creates before persistence', async () => {
    const res = await request(app).post('/api/v1/customers').send({
      firstName: 'Aya',
      lastName: 'Haddad',
      email: 'not-email',
    })

    expect(res.status).toBe(400)
    expect(customerService.createCustomer).not.toHaveBeenCalled()
  })

  it('normalizes valid customer create payloads at the route boundary', async () => {
    const res = await request(app).post('/api/v1/customers').send({
      firstName: '  Aya ',
      lastName: ' Haddad ',
      email: 'AYA@EXAMPLE.TEST',
      phone: ' +212600000000 ',
    })

    expect(res.status).toBe(201)
    expect(customerService.createCustomer).toHaveBeenCalledWith(
      expect.objectContaining({ firstName: 'Aya', lastName: 'Haddad', email: 'aya@example.test', phone: '+212600000000' }),
      'company_1',
    )
  })

  it('rejects invalid license approval decisions before service execution', async () => {
    const res = await request(app).post('/api/v1/customers/customer_1/approve-license').send({ decision: 'REVIEW_LATER' })

    expect(res.status).toBe(400)
    expect(customerService.approveLicense).not.toHaveBeenCalled()
  })

  it('passes license approval actor names to the customer service', async () => {
    const res = await request(app).post('/api/v1/customers/customer_1/approve-license').send({ decision: 'APPROVE', note: 'Readable license' })

    expect(res.status).toBe(200)
    expect(customerService.approveLicense).toHaveBeenCalledWith('customer_1', 'company_1', 'APPROVE', 'Readable license', 'Aya Manager')
  })

  it('caps notification history limits before querying history', async () => {
    const res = await request(app).get('/api/v1/notifications/history?limit=999')

    expect(res.status).toBe(400)
    expect(notificationService.listCompanyHistory).not.toHaveBeenCalled()
  })

  it('uses the analytics summary default period when no query is supplied', async () => {
    const res = await request(app).get('/api/v1/analytics/summary')

    expect(res.status).toBe(200)
    expect(analyticsService.getSummary).toHaveBeenCalledWith('company_1', '30d')
  })
})
