4) API routes (gallery, purchase, designer upload)

server/routes.coverTemplates.ts

import express from "express";
import {
  listCoverTemplates, getCoverTemplate, createCoverTemplate,
  createPurchase
} from "../storage/coverTemplates";
import { ensurePriceForTemplate, createCheckoutSession } from "../stripe/coverCheckout";

const router = express.Router();

// middlewares (replace with your real ones)
const authenticate = (req: any, res: any, next: any) => { if (!req.user) return res.status(401).json({ error: "auth" }); next(); };
const authenticateAdmin = (req: any, res: any, next: any) => next(); // your admin check

// Gallery with filters
router.get("/api/cover-templates", async (req, res) => {
  const q = (req.query.q as string) || undefined;
  const category = (req.query.category as string) || undefined;
  const min = req.query.min ? parseInt(req.query.min as string, 10) : undefined;
  const max = req.query.max ? parseInt(req.query.max as string, 10) : undefined;

  const rows = await listCoverTemplates({ q, category, min, max });
  res.json(rows);
});

router.get("/api/cover-templates/:id", async (req, res) => {
  const tpl = await getCoverTemplate(req.params.id);
  if (!tpl || !tpl.is_active) return res.status(404).json({ error: "Not found" });
  res.json(tpl);
});

// Designer creates a template (creator upload) — admin will activate it later
router.post("/api/creator/cover-templates", authenticate, async (req: any, res) => {
  const { title, category, tags, price_cents, preview_image_url, pptx_url, keynote_url, gslides_url, download_bundle_url } = req.body || {};
  if (!title || !category || !preview_image_url) return res.status(400).json({ error: "Missing fields" });

  const rec = await createCoverTemplate({
    creator_id: req.user.id,
    title, category,
    tags: Array.isArray(tags) ? tags : [],
    price_cents: price_cents ?? 1200,
    currency: "usd",
    preview_image_url,
    pptx_url, keynote_url, gslides_url, download_bundle_url,
    is_active: false
  });
  res.json({ success: true, template: rec });
});

// Checkout: Buy As-Is (or with custom image)
router.post("/api/cover-templates/:id/checkout", authenticate, async (req: any, res) => {
  const tpl = await getCoverTemplate(req.params.id);
  if (!tpl || !tpl.is_active) return res.status(404).json({ error: "Not found" });

  const { customImageUrl } = req.body || {};
  const price = await ensurePriceForTemplate(tpl.id, tpl.title, tpl.price_cents, tpl.currency);

  const successUrl = `${process.env.APP_BASE_URL}/business-assets/templates/cover-dividers?success=true`;
  const cancelUrl = `${process.env.APP_BASE_URL}/business-assets/templates/cover-dividers?cancel=true`;

  const session = await createCheckoutSession({
    priceId: price.id,
    successUrl,
    cancelUrl,
    metadata: { templateId: tpl.id, customImageUrl: customImageUrl || "" }
  });

  await createPurchase({
    user_id: req.user.id,
    template_id: tpl.id,
    custom_image_url: customImageUrl || null,
    amount_cents: tpl.price_cents,
    currency: tpl.currency,
    stripe_session_id: session.id
  });

  res.json({ checkoutUrl: session.url });
});

export default router;