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', role: 'OWNER' }
    next()
  },
  requireCompanyDocumentAuth: (req: any, _res: any, next: any) => {
    req.employee = { id: 'employee_1', role: 'OWNER' }
    next()
  },
}))
vi.mock('../../middleware/requireTenant', () => ({
  requireTenant: (req: any, _res: any, next: any) => {
    req.companyId = 'company_1'
    req.company = { id: 'company_1', name: 'Atlas Cars', slug: 'atlas' }
    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('../../modules/companies/company.service', () => ({
  getCompany: vi.fn(),
  updateCompany: vi.fn(),
  getBrand: vi.fn(),
  updateBrand: vi.fn(),
  uploadLogo: vi.fn(),
  uploadHeroImage: vi.fn(),
  checkSubdomainAvailability: vi.fn(),
  setCustomDomain: vi.fn(),
  getCustomDomainStatus: vi.fn(),
  removeCustomDomain: vi.fn(),
  getContractSettings: vi.fn(),
  updateContractSettings: vi.fn(),
  getInsurancePolicies: vi.fn(),
  createInsurancePolicy: vi.fn(),
  updateInsurancePolicy: vi.fn(),
  deleteInsurancePolicy: vi.fn(),
  getPricingRules: vi.fn(),
  createPricingRule: vi.fn(),
  updatePricingRule: vi.fn(),
  deletePricingRule: vi.fn(),
  getAccountingSettings: vi.fn(),
  updateAccountingSettings: vi.fn(),
  getApiKey: vi.fn(),
  regenerateApiKey: vi.fn(),
}))

import request from 'supertest'
import { createApp } from '../../app'
import * as companyService from '../../modules/companies/company.service'

const app = createApp()

describe('company configuration API contracts', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    vi.mocked(companyService.updateBrand).mockResolvedValue({ id: 'brand_1', displayName: 'Atlas Cars' } as never)
    vi.mocked(companyService.setCustomDomain).mockResolvedValue({ id: 'brand_1', customDomain: 'cars.example.com' } as never)
    vi.mocked(companyService.createInsurancePolicy).mockResolvedValue({ id: 'policy_1' } as never)
    vi.mocked(companyService.createPricingRule).mockResolvedValue({ id: 'rule_1' } as never)
    vi.mocked(companyService.updateAccountingSettings).mockResolvedValue({ id: 'accounting_1' } as never)
  })

  it('rejects invalid public brand email before service execution', async () => {
    const res = await request(app).patch('/api/v1/companies/me/brand').send({ publicEmail: 'not-an-email' })

    expect(res.status).toBe(400)
    expect(companyService.updateBrand).not.toHaveBeenCalled()
  })

  it('passes valid brand settings with tenant identity and company defaults', async () => {
    const res = await request(app).patch('/api/v1/companies/me/brand').send({
      displayName: 'Atlas Premium Cars',
      defaultCurrency: 'MAD',
      paypalEmail: 'billing@example.test',
    })

    expect(res.status).toBe(200)
    expect(companyService.updateBrand).toHaveBeenCalledWith('company_1', {
      displayName: 'Atlas Premium Cars',
      defaultCurrency: 'MAD',
      paypalEmail: 'billing@example.test',
    }, 'Atlas Cars', 'atlas')
  })

  it('rejects invalid custom domains before normalization or persistence', async () => {
    const res = await request(app).post('/api/v1/companies/me/brand/custom-domain').send({ customDomain: 'ab' })

    expect(res.status).toBe(400)
    expect(companyService.setCustomDomain).not.toHaveBeenCalled()
  })

  it('passes custom domain requests with tenant defaults', async () => {
    const res = await request(app).post('/api/v1/companies/me/brand/custom-domain').send({ customDomain: 'Cars.Example.com' })

    expect(res.status).toBe(200)
    expect(companyService.setCustomDomain).toHaveBeenCalledWith('company_1', 'Atlas Cars', 'atlas', 'Cars.Example.com')
  })

  it('applies insurance policy defaults before creating a policy', async () => {
    const res = await request(app).post('/api/v1/companies/me/insurance-policies').send({
      name: 'Basic CDW',
      type: 'CDW',
      chargeType: 'PER_DAY',
      chargeValue: 2500,
    })

    expect(res.status).toBe(201)
    expect(companyService.createInsurancePolicy).toHaveBeenCalledWith('company_1', expect.objectContaining({
      name: 'Basic CDW',
      isRequired: false,
      isActive: true,
      sortOrder: 0,
    }))
  })

  it('rejects malformed pricing rules before service execution', async () => {
    const res = await request(app).post('/api/v1/companies/me/pricing-rules').send({
      name: 'Young driver fee',
      type: 'SURCHARGE',
      condition: 'AGE_LESS_THAN',
      conditionValue: 25,
      adjustmentType: 'PERCENTAGE',
      adjustmentValue: 10.5,
    })

    expect(res.status).toBe(400)
    expect(companyService.createPricingRule).not.toHaveBeenCalled()
  })

  it('validates accounting settings at the route boundary', async () => {
    const invalid = await request(app).patch('/api/v1/companies/me/accounting-settings').send({ fiscalYearStart: 13 })
    expect(invalid.status).toBe(400)
    expect(companyService.updateAccountingSettings).not.toHaveBeenCalled()

    const valid = await request(app).patch('/api/v1/companies/me/accounting-settings').send({ fiscalYearStart: 4, reportFormat: 'BOTH' })
    expect(valid.status).toBe(200)
    expect(companyService.updateAccountingSettings).toHaveBeenCalledWith('company_1', { fiscalYearStart: 4, reportFormat: 'BOTH' })
  })
})
