// src/lib/tenantAccess.ts

import type { Access, PayloadRequest } from 'payload'

/**
 * Ermittelt die Tenant-ID aus dem Request-Host.
 * Gleicht die Domain mit der tenants-Collection ab.
 */
export async function getTenantIdFromHost(req: PayloadRequest): Promise<number | null> {
  try {
    // Host-Header extrahieren (unterstützt verschiedene Formate)
    const headers = req.headers as Headers | Record<string, string | string[] | undefined>
    const host =
      typeof headers.get === 'function'
        ? headers.get('host')
        : (headers as Record<string, string | string[] | undefined>)['host']

    if (!host || typeof host !== 'string') {
      return null
    }

    // Domain normalisieren: Port und www entfernen
    const domain = host.split(':')[0].replace(/^www\./, '').toLowerCase().trim()

    if (!domain) {
      return null
    }

    // Tenant aus Datenbank suchen (domains ist ein Array mit domain-Subfeld)
    const result = await req.payload.find({
      collection: 'tenants',
      where: {
        'domains.domain': { equals: domain },
      },
      limit: 1,
      depth: 0,
    })

    if (result.docs.length > 0 && result.docs[0]?.id) {
      return Number(result.docs[0].id)
    }

    return null
  } catch (error) {
    console.error('[TenantAccess] Error resolving tenant from host:', error)
    return null
  }
}

/**
 * Extracts tenant ID from the where[tenant][equals] query parameter.
 * Used as fallback when the Host header doesn't match any tenant domain
 * (e.g. when the CMS is accessed via cms.c2sgmbh.de by frontend API clients).
 */
function getTenantIdFromQuery(req: PayloadRequest): number | null {
  try {
    const url = req.url ? new URL(req.url, 'http://localhost') : null
    const param = url?.searchParams.get('where[tenant][equals]')
    if (param) {
      const id = Number(param)
      if (!isNaN(id) && id > 0) return id
    }
    return null
  } catch {
    return null
  }
}

/**
 * Access-Control für öffentlich lesbare, aber tenant-isolierte Collections.
 *
 * - Authentifizierte Admin-User: Voller Lesezugriff
 * - Anonyme Requests: Nur Daten des eigenen Tenants
 *
 * Tenant resolution order:
 * 1. Host header (matches tenant domain config)
 * 2. where[tenant][equals] query parameter (for API clients like contracts)
 *
 * The returned access filter ensures tenant isolation regardless of which
 * method resolved the tenant ID.
 */
export const tenantScopedPublicRead: Access = async ({ req }) => {
  // Authentifizierte Admins dürfen alles lesen
  if (req.user) {
    return true
  }

  // Anonyme Requests: Tenant aus Domain oder Query-Parameter ermitteln
  const tenantId = (await getTenantIdFromHost(req)) ?? getTenantIdFromQuery(req)

  if (!tenantId) {
    // Weder gültige Domain noch Tenant-Parameter → kein Zugriff
    return false
  }

  // Nur Dokumente des eigenen Tenants zurückgeben
  return {
    tenant: {
      equals: tenantId,
    },
  }
}

/**
 * Access-Control: Nur authentifizierte User
 */
export const authenticatedOnly: Access = ({ req }) => {
  return !!req.user
}
