/**
 * Subscription + payment REST endpoints.
 *
 * GET    /subscriptions/:userId          — get user subscription
 * POST   /subscriptions                  — create subscription
 * PUT    /subscriptions/:id              — update subscription
 * GET    /payments/:userId               — list user payments
 * POST   /payments                       — record a payment
 */

import type { FastifyInstance } from 'fastify';
import { getRequestProductId } from '../../lib/request-context.js';
import { BadRequestError, NotFoundError } from '../../lib/errors.js';
import * as repo from './repository.js';
import {
  CreateSubscriptionSchema,
  UpdateSubscriptionSchema,
  CreatePaymentSchema,
  type SubscriptionDoc,
  type PaymentDoc,
} from './types.js';

export async function subscriptionRoutes(app: FastifyInstance) {
  // Get subscription by userId
  app.get('/subscriptions/:userId', async req => {
    const { userId } = req.params as { userId: string };
    const productId = getRequestProductId(req);
    const sub = await repo.getByUserId(userId, productId);
    if (!sub) throw new NotFoundError('Subscription not found');
    return sub;
  });

  // Create subscription
  app.post('/subscriptions', async (req, reply) => {
    const parsed = CreateSubscriptionSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }
    const input = parsed.data;
    const now = new Date();
    const periodEnd = new Date(now);
    if (input.trialDays && input.trialDays > 0) {
      periodEnd.setDate(periodEnd.getDate() + input.trialDays);
    } else {
      periodEnd.setMonth(periodEnd.getMonth() + 1);
    }

    const productId = getRequestProductId(req);
    const doc: SubscriptionDoc = {
      id: `sub_${input.userId}_${Date.now()}`,
      productId,
      userId: input.userId,
      plan: input.plan,
      status: input.status,
      currentPeriodStart: now.toISOString(),
      currentPeriodEnd: periodEnd.toISOString(),
      cancelAtPeriodEnd: false,
      monthlyPrice: input.monthlyPrice,
      tokensIncluded: input.tokensIncluded,
      tokensUsed: 0,
      ...(input.stripeCustomerId && { stripeCustomerId: input.stripeCustomerId }),
      ...(input.stripeSubscriptionId && { stripeSubscriptionId: input.stripeSubscriptionId }),
      createdAt: now.toISOString(),
      updatedAt: now.toISOString(),
    };
    const created = await repo.createSubscription(doc);
    reply.code(201);
    return created;
  });

  // Update subscription by userId (looks up subscription, then updates)
  app.put('/subscriptions/:userId', async req => {
    const { userId } = req.params as { userId: string };

    const parsed = UpdateSubscriptionSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }
    const productId = getRequestProductId(req);
    const existing = await repo.getByUserId(userId, productId);
    if (!existing) throw new NotFoundError('Subscription not found');
    const updated = await repo.updateSubscription(existing.id, userId, parsed.data);
    if (!updated) throw new NotFoundError('Subscription update failed');
    return updated;
  });

  // List payments
  app.get('/payments/:userId', async req => {
    const { userId } = req.params as { userId: string };
    const { limit = '50' } = req.query as { limit?: string };
    const productId = getRequestProductId(req);
    return { payments: await repo.getPaymentsByUser(userId, productId, Number(limit)) };
  });

  // Create payment
  app.post('/payments', async (req, reply) => {
    const parsed = CreatePaymentSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }
    const input = parsed.data;
    const productId = getRequestProductId(req);
    const doc: PaymentDoc = {
      id: `pay_${crypto.randomUUID()}`,
      productId,
      ...input,
      createdAt: new Date().toISOString(),
    };
    const created = await repo.createPayment(doc);
    reply.code(201);
    return created;
  });
}
