import Fastify from 'fastify'
import cors from '@fastify/cors'
import Stripe from 'stripe'
import dotenv from 'dotenv'
import { setupAdmin } from './admin.mjs'
import { prisma } from './src/lib/db.mjs'

dotenv.config()

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY ?? '')
const DOMAIN = process.env.DOMAIN ?? 'http://localhost:4321'

const app = Fastify({ logger: true, trustProxy: true })
await app.register(cors, { origin: '*', methods: ['GET', 'POST'] })

// ── Webhook Stripe (AVANT AdminJS pour éviter les conflits de body parsing) ─
app.post('/api/webhook', {
  config: { rawBody: true },
  onRequest: (request, reply, done) => {
    request.rawBody = ''
    request.req.on('data', chunk => { request.rawBody += chunk })
    request.req.on('end', done)
  },
}, async (request, reply) => {
  const sig           = request.headers['stripe-signature']
  const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET
  if (!sig || !webhookSecret) return reply.code(400).send('Missing signature')

  let event
  try {
    event = stripe.webhooks.constructEvent(request.rawBody, sig, webhookSecret)
  } catch {
    return reply.code(400).send('Webhook Error')
  }

  if (event.type === 'checkout.session.completed') {
    const session = event.data.object
    if (session.payment_status === 'paid') {
      app.log.info(`✓ Paiement — ${session.id} — ${session.customer_details?.email}`)

      // Find product by stripeKey
      const stripeKey = session.metadata?.product
      const product = stripeKey
        ? await prisma.product.findFirst({ where: { stripeKey } })
        : null

      await prisma.order.upsert({
        where: { stripeSessionId: session.id },
        create: {
          stripeSessionId: session.id,
          stripePaymentIntent: typeof session.payment_intent === 'string' ? session.payment_intent : null,
          status: 'paid',
          amount: session.amount_total ?? 0,
          currency: session.currency ?? 'eur',
          customerEmail: session.customer_details?.email ?? null,
          productId: product?.id ?? null,
          productSlug: product?.slug ?? stripeKey ?? null,
          metadata: session.metadata ?? null,
        },
        update: { status: 'paid' },
      })
    }
  }
  return { received: true }
})

// ── AdminJS ─────────────────────────────────────────────────────────────────
await setupAdmin(app)

// ── SEO ─────────────────────────────────────────────────────────────────────
app.get('/robots.txt', (_, reply) => {
  reply
    .type('text/plain')
    .header('Cache-Control', 'public, max-age=86400')
    .send(`User-agent: *\nAllow: /\nSitemap: ${DOMAIN}/sitemap.xml\n`)
})

app.get('/sitemap.xml', async (_, reply) => {
  const today = new Date().toISOString().split('T')[0]
  const products = await prisma.product.findMany({
    where: { isPublished: true },
    select: { slug: true },
  })
  const productUrls = products
    .map(p => `  <url><loc>${DOMAIN}/collection/${p.slug}</loc><lastmod>${today}</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url>`)
    .join('\n')

  reply
    .type('application/xml')
    .header('Cache-Control', 'public, max-age=86400')
    .send(
      `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n  <url><loc>${DOMAIN}/</loc><lastmod>${today}</lastmod><changefreq>weekly</changefreq><priority>1.0</priority></url>\n${productUrls}\n</urlset>`
    )
})

// ── Health check ────────────────────────────────────────────────────────────
app.get('/api/health', async () => ({ status: 'ok' }))

// ── Checkout Stripe ─────────────────────────────────────────────────────────
app.post('/api/checkout', async (request, reply) => {
  const { product, email } = request.body ?? {}

  // Lookup by stripeKey (compat frontend: "lumiere_orbitale")
  const p = await prisma.product.findFirst({
    where: { stripeKey: product, isPublished: true },
    select: { stripePriceId: true, stripeKey: true },
  })
  if (!p || !p.stripePriceId) return reply.code(404).send({ error: 'Produit inconnu' })

  let session
  try {
    session = await stripe.checkout.sessions.create({
      mode: 'payment',
      payment_method_types: ['card', 'link'],
      line_items: [{
        price: p.stripePriceId,
        quantity: 1,
      }],
      metadata:       { product },
      success_url:    `${DOMAIN}/success?session_id={CHECKOUT_SESSION_ID}`,
      cancel_url:     `${DOMAIN}/#collection`,
      locale:         'fr',
      customer_email: email ?? undefined,
      custom_text: {
        submit: { message: 'Pièce unique — fabriquée à Paris. Délai : 6 à 8 semaines.' },
      },
    })
  } catch (err) {
    app.log.error(err)
    return reply.code(500).send({ error: err.message })
  }
  return { url: session.url }
})

// ── Vérification session ────────────────────────────────────────────────────
app.get('/api/session/:id', async (request) => {
  const session = await stripe.checkout.sessions.retrieve(request.params.id, {
    expand: ['payment_intent.latest_charge'],
  })
  const charge = session.payment_intent?.latest_charge
  return {
    status:         session.payment_status,
    amount:         session.amount_total,
    currency:       session.currency,
    customer_email: session.customer_details?.email ?? null,
    product:        session.metadata?.product ?? null,
    receipt_url:    charge?.receipt_url ?? null,
  }
})

// ── Start ───────────────────────────────────────────────────────────────────
try {
  await app.listen({ port: process.env.PORT ?? 3000, host: '0.0.0.0' })
} catch (err) {
  app.log.error(err)
  process.exit(1)
}
