// Guard tests for DomainsService.add(): one workspace per domain platform-wide,
// and the platform's own namespace (PLATFORM_TENANT_DOMAIN) is reserved — the
// apex only for the dezky tenant, everything under it for nobody. The service
// is constructed directly with minimal mocks; Stalwart is "not configured" so
// the happy path skips provisioning.

import { ConflictException } from '@nestjs/common'
import { Types } from 'mongoose'
import { DomainsService, type TenantRef } from './domains.service.js'

const ACTOR = { kind: 'user', id: 'test', label: 'test' } as unknown as Parameters<
  DomainsService['add']
>[2]

function makeService(opts: { takenByOtherTenant?: boolean } = {}) {
  const created: Record<string, unknown>[] = []
  const domainModel = {
    findOne: () => ({ exec: async () => null }),
    exists: async () => (opts.takenByOtherTenant ? { _id: new Types.ObjectId() } : null),
    countDocuments: async () => 0,
    create: async (doc: Record<string, unknown>) => {
      created.push(doc)
      // runChecks mutates and saves the doc; give it the bits it touches.
      return {
        ...doc,
        records: doc.records ?? [],
        ownershipVerified: false,
        markModified: () => {},
        save: async () => {},
      }
    },
  }
  const tenantModel = { updateOne: () => ({ exec: async () => ({}) }) }
  const userModel = { countDocuments: () => ({ exec: async () => 0 }) }
  const stalwart = { configured: false }
  const dns = { check: async () => ({ observed: [], status: 'pending' }) }
  const audit = { record: async () => {} }
  const svc = new DomainsService(
    domainModel as never,
    tenantModel as never,
    userModel as never,
    stalwart as never,
    dns as never,
    audit as never,
  )
  return { svc, created }
}

const tenant = (slug: string, isPlatformTenant = false): TenantRef => ({
  _id: new Types.ObjectId(),
  slug,
  isPlatformTenant,
})

const BASE = process.env.PLATFORM_TENANT_DOMAIN || 'dezky.local'

describe('DomainsService.add guards', () => {
  it('rejects a domain already used by another workspace', async () => {
    const { svc } = makeService({ takenByOtherTenant: true })
    await expect(svc.add(tenant('acme'), 'example.com', ACTOR)).rejects.toThrow(
      ConflictException,
    )
    await expect(svc.add(tenant('acme'), 'example.com', ACTOR)).rejects.toThrow(
      /another workspace/,
    )
  })

  it('rejects the platform apex for any non-platform tenant', async () => {
    const { svc } = makeService()
    await expect(svc.add(tenant('acme'), BASE, ACTOR)).rejects.toThrow(/reserved/)
    // Even a tenant that happens to be NAMED dezky — the flag decides, not the slug.
    await expect(svc.add(tenant('dezky'), BASE, ACTOR)).rejects.toThrow(/reserved/)
  })

  it('rejects anything under the platform namespace for everyone', async () => {
    const { svc } = makeService()
    await expect(svc.add(tenant('acme'), `foo.${BASE}`, ACTOR)).rejects.toThrow(/reserved/)
    // Even the platform tenant can't claim service/infra hostnames.
    await expect(svc.add(tenant('dezky', true), `mail.${BASE}`, ACTOR)).rejects.toThrow(/reserved/)
  })

  it('allows the flagged platform tenant to claim the apex, whatever its slug', async () => {
    const { svc, created } = makeService()
    const view = await svc.add(tenant('dezky-aps', true), BASE, ACTOR)
    expect(view.domain).toBe(BASE)
    expect(created).toHaveLength(1)
  })
})
