'use server'

import { createClient } from '@/lib/supabase/server'
import { revalidatePath } from 'next/cache'
import { sendMail } from '@/utils/mail'
import { InvoicePDF } from '@/components/invoice-pdf'
import { renderToBuffer } from '@react-pdf/renderer'
import React from 'react'
import { buildCustomerSnapshot, buildOrderSnapshot } from '@/lib/license-transform'
import type { Category, EndCustomer, Order, Product, Profile, WizardSelections } from '@/lib/types'
import { getProducts, getCategories } from '@/lib/actions/products'

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

/**
 * Erzeugt eine menschenlesbare, nicht-sequenzielle Bestellnummer.
 * Format: RE-YYYY-NNNNN (z.B. RE-2026-84731)
 * Kein Rückschluss auf Gesamtanzahl der Bestellungen möglich.
 */
function generateOrderNumber(): string {
  const year = new Date().getFullYear()
  const rand = Math.floor(10000 + Math.random() * 90000) // 5-stellig, niemals < 10000
  return `RE-${year}-${rand}`
}

/**
 * Erstellt einen einfachen deterministischen Hash aus dem Bestell-Snapshot.
 * Wird für den Idempotenz-Guard verwendet (verhindert Doppelbestellungen).
 */
function hashOrderSnapshot(snapshot: object): string {
  const str = JSON.stringify(snapshot)
  let hash = 0
  for (let i = 0; i < str.length; i++) {
    const char = str.charCodeAt(i)
    hash = ((hash << 5) - hash) + char
    hash = hash & hash // 32-bit integer
  }
  return Math.abs(hash).toString(36)
}

// ─── submitOrder ──────────────────────────────────────────────────────────────

/**
 * Speichert eine abgeschlossene Bestellung als versionierten Snapshot in der DB,
 * generiert die PDF-Rechnung und lädt sie in den Supabase Storage hoch.
 *
 * Enthält Idempotenz-Guard: Wenn innerhalb von 30 Sekunden eine identische
 * Bestellung vom gleichen User existiert, wird diese zurückgegeben statt
 * einer neuen erstellt (Schutz gegen Doppelklick / Netzwerk-Retry).
 */
export async function submitOrder(params: {
  selections: WizardSelections
  moduleQuantities?: Record<string, number>
  products?: Product[]
  categories?: Category[]
  customerProfile: Partial<Profile>
  endCustomerId?: string | null
  endCustomer?: EndCustomer | null
  billingInterval?: 'one_time' | 'monthly'
}): Promise<Order> {
  const { selections, moduleQuantities, customerProfile, endCustomerId, endCustomer, billingInterval } = params
  const supabase = await createClient()

  const { data: { user } } = await supabase.auth.getUser()
  if (!user) throw new Error('Not authenticated')

  // Fetch catalog directly from DB to prevent client tampering
  const dbProducts = await getProducts()
  const dbCategories = await getCategories()

  // ─── Constraint Validation ──────────────────────────────────────────────────
  for (const cat of dbCategories) {
    const sel = selections[cat.id]
    if (cat.is_required && (!sel || !sel.productId)) {
      throw new Error(`Die Kategorie "${cat.name}" ist ein Pflichtfeld, wurde aber nicht ausgewählt.`)
    }
    if (sel?.productId) {
      const prod = dbProducts.find(p => p.id === sel.productId)
      if (!prod) {
        throw new Error(`Das ausgewählte Produkt für Kategorie "${cat.name}" wurde nicht gefunden.`)
      }
      
      // Validate selected modules
      for (const mId of sel.moduleIds) {
        const mod = prod.modules?.find(m => m.id === mId)
        if (!mod) {
          throw new Error(`Das Modul mit ID "${mId}" gehört nicht zum Produkt "${prod.name}".`)
        }
        // Requirements check
        if (mod.requirements && mod.requirements.length > 0) {
          const missing = mod.requirements.filter(reqId => !sel.moduleIds.includes(reqId))
          if (missing.length > 0) {
            throw new Error(`Das Modul "${mod.name}" setzt die Aktivierung anderer Module voraus.`)
          }
        }
        // Exclusions check
        if (mod.exclusions && mod.exclusions.length > 0) {
          const conflicting = mod.exclusions.filter(exId => sel.moduleIds.includes(exId))
          if (conflicting.length > 0) {
            throw new Error(`Das Modul "${mod.name}" schließt die Kombination mit anderen gewählten Modulen aus.`)
          }
        }
      }
    }
  }

  // Product-level constraints validation
  const selectedProductIds = Object.values(selections)
    .map(s => s.productId)
    .filter((id): id is string => !!id)

  for (const prodId of selectedProductIds) {
    const prod = dbProducts.find(p => p.id === prodId)
    if (!prod) continue

    // Product requirements check
    if (prod.requirements && prod.requirements.length > 0) {
      const missing = prod.requirements.filter(reqId => !selectedProductIds.includes(reqId))
      if (missing.length > 0) {
        const missingNames = missing
          .map(reqId => dbProducts.find(p => p.id === reqId)?.name || reqId)
          .join(', ')
        throw new Error(`Das Produkt "${prod.name}" erfordert die Auswahl von: ${missingNames}.`)
      }
    }

    // Product exclusions check
    if (prod.exclusions && prod.exclusions.length > 0) {
      const conflicting = prod.exclusions.filter(exId => selectedProductIds.includes(exId))
      if (conflicting.length > 0) {
        const conflictingNames = conflicting
          .map(exId => dbProducts.find(p => p.id === exId)?.name || exId)
          .join(', ')
        throw new Error(`Das Produkt "${prod.name}" schließt die gleichzeitige Auswahl von folgenden Produkten aus: ${conflictingNames}.`)
      }
    }
  }

  // 1. Snapshots aufbauen
  // Wenn Endkunde vorhanden: dessen Daten einfrieren; sonst Partner-Profil (Fallback)
  const customerSnapshot = buildCustomerSnapshot(customerProfile, endCustomer ?? null)
  const orderSnapshot = buildOrderSnapshot(selections, dbProducts, dbCategories, billingInterval, moduleQuantities)

  // 2. Idempotenz-Guard: Prüfen ob identische Bestellung in den letzten 30s existiert
  const orderHash = hashOrderSnapshot(orderSnapshot)
  const thirtySecondsAgo = new Date(Date.now() - 30_000).toISOString()

  const { data: existingOrder } = await supabase
    .from('orders')
    .select('*')
    .eq('user_id', user.id)
    .eq('order_hash', orderHash)
    .gte('created_at', thirtySecondsAgo)
    .maybeSingle()

  if (existingOrder) {
    console.warn('[submitOrder] Duplicate order detected, returning existing order:', existingOrder.order_number)
    return existingOrder as Order
  }

  // 3. Eindeutige Bestellnummer generieren (Retry bei Kollision)
  let orderNumber: string = ''
  for (let attempt = 0; attempt < 5; attempt++) {
    const candidate = generateOrderNumber()
    const { data: collision } = await supabase
      .from('orders')
      .select('id')
      .eq('order_number', candidate)
      .maybeSingle()
    if (!collision) {
      orderNumber = candidate
      break
    }
  }
  if (!orderNumber) throw new Error('Konnte keine eindeutige Bestellnummer generieren.')

  // 4. Bestellung in DB schreiben
  const { data: order, error: orderError } = await supabase
    .from('orders')
    .insert([{
      user_id: user.id,
      order_number: orderNumber,
      order_hash: orderHash,
      end_customer_id: endCustomerId ?? null,
      total_price: orderSnapshot.total,
      customer_data: customerSnapshot,
      order_data: orderSnapshot,
      status: 'pending',
    }])
    .select()
    .single()

  if (orderError) throw orderError

  // 5. PDF generieren (greift auf Snapshot-Daten zu, nicht auf Live-Katalog)
  try {
    const buffer = await renderToBuffer(
      React.createElement(InvoicePDF, {
        order,
        customer: customerSnapshot,
        orderSnapshot,
      })
    )

    // 6. PDF in Supabase Storage hochladen
    const fileName = `invoice_${order.id}.pdf`
    const { error: uploadError } = await supabase
      .storage
      .from('invoices')
      .upload(fileName, buffer, { contentType: 'application/pdf', upsert: true })

    if (uploadError) {
      console.error('PDF Upload Error:', uploadError)
    } else {
      const { data: publicUrlData } = supabase.storage.from('invoices').getPublicUrl(fileName)
      await supabase.from('orders').update({ pdf_url: publicUrlData.publicUrl }).eq('id', order.id)
      order.pdf_url = publicUrlData.publicUrl
    }

    // 7. E-Mail mit PDF-Anhang an den Besteller senden
    if (user.email) {
      try {
        const formattedDate = new Date(order.created_at).toLocaleDateString('de-DE')
        const formattedTotal = order.total_price.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' })
        
        await sendMail({
          to: user.email,
          subject: `Bestellbestätigung ${orderNumber}`,
          text: `Hallo,\n\nvielen Dank für Ihre Bestellung bei CASPOS Shop!\n\nBestelldetails:\n- Bestellnummer: ${orderNumber}\n- Datum: ${formattedDate}\n- Endkunde: ${customerSnapshot.company_name}\n- Gesamtsumme: ${formattedTotal}\n\nIm Anhang dieser E-Mail finden Sie Ihre Bestellbestätigung als PDF-Dokument.\n\nViele Grüße,\nIhr CASPOS Shop-Team`,
          html: `
            <div style="font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e2e8f0; border-radius: 8px;">
              <h2 style="color: #0f172a; margin-bottom: 16px;">Vielen Dank für Ihre Bestellung!</h2>
              <p style="color: #475569; font-size: 16px; line-height: 1.5;">Hallo,</p>
              <p style="color: #475569; font-size: 16px; line-height: 1.5;">wir freuen uns sehr über Ihre Bestellung bei CASPOS Shop. Ihre Bestellung wurde erfolgreich entgegengenommen und wird nun verarbeitet.</p>
              <div style="background-color: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px; padding: 16px; margin: 24px 0;">
                <h3 style="color: #0f172a; margin-top: 0; margin-bottom: 12px;">Bestelldetails</h3>
                <table style="width: 100%; border-collapse: collapse; font-size: 14px; color: #475569;">
                  <tr>
                    <td style="padding: 4px 0; font-weight: bold; width: 140px;">Bestellnummer:</td>
                    <td style="padding: 4px 0;">${orderNumber}</td>
                  </tr>
                  <tr>
                    <td style="padding: 4px 0; font-weight: bold;">Datum:</td>
                    <td style="padding: 4px 0;">${formattedDate}</td>
                  </tr>
                  <tr>
                    <td style="padding: 4px 0; font-weight: bold;">Endkunde:</td>
                    <td style="padding: 4px 0;">${customerSnapshot.company_name}</td>
                  </tr>
                  <tr>
                    <td style="padding: 4px 0; font-weight: bold;">Gesamtsumme:</td>
                    <td style="padding: 4px 0; font-weight: bold; color: #0f172a;">${formattedTotal}</td>
                  </tr>
                </table>
              </div>
              <p style="color: #475569; font-size: 16px; line-height: 1.5;">Im Anhang dieser E-Mail finden Sie Ihre Bestellbestätigung als PDF-Dokument.</p>
              <p style="color: #475569; font-size: 16px; line-height: 1.5; margin-top: 24px;">Mit freundlichen Grüßen,<br>Ihr CASPOS Shop-Team</p>
              <hr style="border: 0; border-top: 1px solid #e2e8f0; margin: 24px 0;">
              <p style="color: #94a3b8; font-size: 12px; text-align: center;">Diese E-Mail wurde automatisch generiert. Bitte antworten Sie nicht darauf.</p>
            </div>
          `,
          attachments: [
            {
              filename: `Bestellbestaetigung_${orderNumber}.pdf`,
              content: buffer,
              contentType: 'application/pdf',
            }
          ]
        })
      } catch (mailError) {
        console.error('Failed to send order confirmation mail:', mailError)
      }
    }
  } catch (pdfError) {
    console.error('PDF Generation Error:', pdfError)
  }

  revalidatePath('/my-customers')
  revalidatePath('/my-orders')
  return order as Order
}
