import { Router } from 'express' import { requireCompanyAuth } from '../../middleware/requireCompanyAuth' import { requireTenant } from '../../middleware/requireTenant' import { requireSubscriptionRead, requireSubscriptionFull } from '../../middleware/requireSubscription' import { requireRole } from '../../middleware/requireRole' import { parseBody } from '../../http/validate' import { ok } from '../../http/respond' import { getRawBodyString, parseRawJsonBody } from '../../http/webhooks' import * as amanpay from '../../services/amanpayService' import * as paypal from '../../services/paypalService' import * as service from './subscription.service' import { checkoutSchema, changePlanSchema, capturePaypalSchema, startTrialSchema, cancelSchema, reactivateSchema, } from './subscription.schemas' const publicRouter = Router() const webhookRouter = Router() const router = Router() // ─── Public ──────────────────────────────────────────────────── publicRouter.get('/plans', (_req, res, next) => { service.getPlans().then((d: any) => ok(res, d)).catch(next) }) publicRouter.get('/providers', (_req, res) => { ok(res, service.getProviders()) }) publicRouter.get('/features', (_req, res, next) => { service.getPlanFeatures().then((d: any) => ok(res, d)).catch(next) }) // ─── Webhooks (no auth) ──────────────────────────────────────── webhookRouter.post('/webhooks/amanpay', async (req, res, next) => { try { const rawBody = getRawBodyString(req) const payload = parseRawJsonBody(req) const signature = (req.headers['x-amanpay-signature'] as string) ?? '' if (!amanpay.isConfigured() || !amanpay.verifyWebhookSignature(rawBody, signature)) { return res.status(401).json({ error: 'invalid_signature' }) } await service.handleAmanpayWebhook(payload, rawBody) res.json({ received: true }) } catch (err) { next(err) } }) webhookRouter.post('/webhooks/paypal', async (req, res, next) => { try { const rawBody = getRawBodyString(req) const payload = parseRawJsonBody(req) const isValid = await paypal.verifyWebhookEvent(req.headers as Record, rawBody) if (!paypal.isConfigured() || !isValid) return res.status(401).json({ error: 'invalid_signature' }) await service.handlePaypalWebhook(payload, rawBody) res.json({ received: true }) } catch (err) { next(err) } }) // ─── PayPal capture (auth but no subscription check) ────────── router.post('/capture-paypal', requireCompanyAuth, requireTenant, requireSubscriptionFull, requireRole('OWNER'), async (req, res, next) => { try { const { paypalOrderId } = parseBody(capturePaypalSchema, req) ok(res, await service.capturePaypal(req.companyId, paypalOrderId)) } catch (err) { next(err) } }) // ─── Authenticated ───────────────────────────────────────────── router.use(requireCompanyAuth, requireTenant, requireSubscriptionRead) router.get('/me', async (req, res, next) => { try { ok(res, await service.getSubscription(req.companyId)) } catch (err) { next(err) } }) router.get('/invoices', async (req, res, next) => { try { ok(res, await service.getInvoices(req.companyId)) } catch (err) { next(err) } }) router.get('/events', async (req, res, next) => { try { ok(res, await service.getEvents(req.companyId)) } catch (err) { next(err) } }) router.get('/entitlement', async (req, res, next) => { try { ok(res, await service.getEntitlement(req.companyId)) } catch (err) { next(err) } }) router.post('/trial', requireSubscriptionFull, requireRole('OWNER'), async (req, res, next) => { try { const body = parseBody(startTrialSchema, req) ok(res, await service.startTrial(req.companyId, body.plan, body.billingPeriod, body.currency)) } catch (err) { next(err) } }) router.post('/checkout', requireSubscriptionFull, requireRole('OWNER'), async (req, res, next) => { try { const body = parseBody(checkoutSchema, req) ok(res, await service.checkout(req.companyId, body)) } catch (err) { next(err) } }) router.post('/reactivate', requireSubscriptionFull, requireRole('OWNER'), async (req, res, next) => { try { const body = parseBody(reactivateSchema, req) ok(res, await service.reactivate(req.companyId, body)) } catch (err) { next(err) } }) router.post('/change-plan', requireSubscriptionFull, requireRole('OWNER'), async (req, res, next) => { try { const body = parseBody(changePlanSchema, req) ok(res, await service.changePlan(req.companyId, body)) } catch (err) { next(err) } }) router.post('/cancel', requireSubscriptionFull, requireRole('OWNER'), async (req, res, next) => { try { const { mode, reason } = parseBody(cancelSchema, req) ok(res, await service.cancel(req.companyId, mode, reason)) } catch (err) { next(err) } }) router.post('/resume', requireSubscriptionFull, requireRole('OWNER'), async (req, res, next) => { try { ok(res, await service.resume(req.companyId)) } catch (err) { next(err) } }) export default router export { publicRouter as subscriptionPublicRouter, webhookRouter as subscriptionWebhookRouter }