/**
 * license-transform.ts
 *
 * Transformationsschicht: Wandelt den Wizard-Zustand in strukturierte
 * Datenstrukturen für DB-Speicherung (OrderSnapshot) und Lizenzserver (LicenseBundle) um.
 */

import type {
  Category,
  CategorySelection,
  CustomerSnapshot,
  EndCustomer,
  LicenseBundle,
  LicenseOption,
  OrderItem,
  OrderSnapshot,
  Product,
  Profile,
  WizardSelections,
} from '@/lib/types'

// ─── Hilfsfunktionen ─────────────────────────────────────────────────────────

/**
 * Wandelt einen Produktnamen in einen stabilen, URL-sicheren Slug um.
 * Beispiel: "CASPOS Basic" → "caspos_basic"
 */
export function slugify(name: string): string {
  return name
    .toLowerCase()
    .replace(/ä/g, 'ae')
    .replace(/ö/g, 'oe')
    .replace(/ü/g, 'ue')
    .replace(/ß/g, 'ss')
    .replace(/[^a-z0-9]+/g, '_')
    .replace(/^_|_$/g, '')
}

/**
 * Baut einen validen CustomerSnapshot aus einem Profil oder Formulardaten.
 *
 * Wenn ein Endkunde übergeben wird, werden DESSEN Daten eingefroren (für die Rechnung).
 * Ohne Endkunden-Übergabe: Partner-Profil als Fallback (Abwärtskompatibilität).
 * Fehlende Pflichtfelder werden mit leerem String aufgefüllt (Validierung im Wizard).
 */
export function buildCustomerSnapshot(
  profile: Partial<Profile>,
  endCustomer?: EndCustomer | null
): CustomerSnapshot {
  if (endCustomer) {
    return {
      schema_version: 1,
      end_customer_id: endCustomer.id,
      company_name: endCustomer.company_name ?? '',
      vat_id: endCustomer.vat_id ?? '',
      first_name: endCustomer.first_name ?? '',
      last_name: endCustomer.last_name ?? '',
      address: endCustomer.street ?? '',
      zip_code: endCustomer.zip ?? '',
      city: endCustomer.city ?? '',
    }
  }
  return {
    schema_version: 1,
    company_name: profile.company_name ?? '',
    vat_id: profile.vat_id ?? '',
    first_name: profile.first_name ?? '',
    last_name: profile.last_name ?? '',
    address: profile.address ?? '',
    zip_code: profile.zip_code ?? '',
    city: profile.city ?? '',
    ...(profile.email ? { email: profile.email } : {}),
  }
}

// ─── OrderSnapshot ────────────────────────────────────────────────────────────

/**
 * Baut den unveränderlichen OrderSnapshot für die JSONB-Spalte `orders.order_data`.
 *
 * WICHTIG: Alle Namen und Preise werden hier eingefroren (Snapshot-Prinzip).
 * Spätere Änderungen am Produktkatalog brechen keine historischen Bestellungen.
 */
export function buildOrderSnapshot(
  selections: WizardSelections,
  products: Product[],
  categories: Category[],
  billingInterval?: 'one_time' | 'monthly',
  moduleQuantities?: Record<string, number>
): OrderSnapshot {
  const items: OrderItem[] = []
  let subtotal = 0
  let dominantTaxRate = 19 // Fallback; wird durch das erste Produkt mit tax_rate überschrieben

  for (const cat of categories) {
    const sel: CategorySelection | undefined = selections[cat.id]
    if (!sel?.productId) continue

    const prod = products.find((p) => p.id === sel.productId)
    if (!prod) continue

    dominantTaxRate = prod.tax_rate

    const selectedModules = sel.moduleIds
      .map((modId) => prod.modules?.find((m) => m.id === modId))
      .filter((m): m is NonNullable<typeof m> => !!m)
      .map((mod) => {
        const qty = moduleQuantities?.[mod.id] || 1
        return {
          module_id: mod.id,
          module_name: mod.name,
          price: mod.price,
          quantity: qty,
          total_price: mod.price * qty,
        }
      })

    const moduleTotal = selectedModules.reduce((acc, m) => acc + (m.total_price || m.price), 0)
    const itemTotal = prod.base_price + moduleTotal
    subtotal += itemTotal

    items.push({
      category_id: cat.id,
      category_name: cat.name,
      product_id: prod.id,
      product_name: prod.name,
      base_price: prod.base_price,
      billing_interval: prod.billing_interval,
      selected_modules: selectedModules,
      item_total: itemTotal,
    })
  }

  const taxAmount = Math.round(subtotal * (dominantTaxRate / 100) * 100) / 100
  const total = Math.round((subtotal + taxAmount) * 100) / 100

  // Wenn billingInterval übergeben, dieses nutzen; sonst automatisch ermitteln
  const billingCycle = billingInterval || (items.every((i) => i.billing_interval === 'one_time')
    ? 'one_time'
    : 'monthly')

  return {
    schema_version: 1,
    billing_cycle: billingCycle,
    items,
    subtotal,
    tax_rate: dominantTaxRate,
    tax_amount: taxAmount,
    total,
  }
}

// ─── LicenseBundle ────────────────────────────────────────────────────────────

/**
 * Transformiert einen gespeicherten OrderSnapshot (oder den aktuellen Wizard-Zustand)
 * in ein LicenseBundle für den Lizenzserver / das ERP-System.
 *
 * Jedes Produkt und jedes Modul wird auf einen stabilen `key` (Slug) gemappt,
 * der als Identifier im Lizenzserver verwendet werden kann.
 */
export function transformToLicenseBundle(
  selections: WizardSelections,
  products: Product[],
  categories: Category[],
  customer: Partial<Profile>,
  moduleQuantities?: Record<string, number>
): LicenseBundle {
  const options: LicenseOption[] = []
  let monthlyTotal = 0
  let oneTimeTotal = 0

  for (const cat of categories) {
    const sel: CategorySelection | undefined = selections[cat.id]
    if (!sel?.productId) continue

    const prod = products.find((p) => p.id === sel.productId)
    if (!prod) continue

    const prodKey = slugify(prod.name)

    options.push({
      key: prodKey,
      label: prod.name,
      active: true,
      billing: prod.billing_interval,
      price_net: prod.base_price,
    })

    if (prod.billing_interval === 'monthly') monthlyTotal += prod.base_price
    else oneTimeTotal += prod.base_price

    for (const modId of sel.moduleIds) {
      const mod = prod.modules?.find((m) => m.id === modId)
      if (!mod) continue
      const qty = moduleQuantities?.[mod.id] || 1

      options.push({
        key: `${prodKey}__${slugify(mod.name)}`,
        label: mod.name,
        active: true,
        // Module erben das Billing-Intervall des übergeordneten Produkts
        billing: prod.billing_interval,
        price_net: mod.price,
        quantity: qty,
      })

      if (prod.billing_interval === 'monthly') monthlyTotal += mod.price * qty
      else oneTimeTotal += mod.price * qty
    }
  }

  return {
    customer_ref: customer.company_name ?? customer.last_name ?? 'unknown',
    generated_at: new Date().toISOString(),
    license_key_prefix: `CASP-${new Date().getFullYear()}-`,
    options,
    monthly_total_net: monthlyTotal,
    one_time_total_net: oneTimeTotal,
  }
}

/**
 * Rekonstruiert ein LicenseBundle direkt aus einem gespeicherten OrderSnapshot
 * (ohne Zugriff auf den Live-Katalog – gut für historische Bestellungen).
 */
export function licenseBundleFromSnapshot(
  snapshot: OrderSnapshot,
  customerRef: string
): LicenseBundle {
  const options: LicenseOption[] = []
  let monthlyTotal = 0
  let oneTimeTotal = 0

  for (const item of snapshot.items) {
    const prodKey = slugify(item.product_name)

    options.push({
      key: prodKey,
      label: item.product_name,
      active: true,
      billing: item.billing_interval,
      price_net: item.base_price,
    })

    if (item.billing_interval === 'monthly') monthlyTotal += item.base_price
    else oneTimeTotal += item.base_price

    for (const mod of item.selected_modules) {
      const qty = mod.quantity || 1
      const modPrice = mod.total_price || (mod.price * qty)
      options.push({
        key: `${prodKey}__${slugify(mod.module_name)}`,
        label: mod.module_name,
        active: true,
        billing: item.billing_interval,
        price_net: mod.price,
        quantity: qty,
      })

      if (item.billing_interval === 'monthly') monthlyTotal += modPrice
      else oneTimeTotal += modPrice
    }
  }

  return {
    customer_ref: customerRef,
    generated_at: new Date().toISOString(),
    license_key_prefix: `CASP-${new Date().getFullYear()}-`,
    options,
    monthly_total_net: monthlyTotal,
    one_time_total_net: oneTimeTotal,
  }
}
