import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { wrap } from "@typeschema/valibot";
import { createTRPCRouter, protectedProcedure } from "../utils";
import {
  CreateCheckoutSessionSchema,
  CreatePortalSessionSchema,
  CancelSubscriptionSchema,
  ReactivateSubscriptionSchema,
  ListInvoicesSchema,
} from "../schemas/billing";
import {
  getOrCreateCustomer,
  createCheckoutSession,
  createPortalSession,
  cancelSubscription,
  reactivateSubscription,
  listInvoices,
} from "~/server/services/billing.service";
import { db } from "~/server/db";
import { subscriptions } from "~/server/db/schema/subscription";

export const billingRouter = createTRPCRouter({
  getSubscription: protectedProcedure.query(async ({ ctx }) => {
    const sub = await db.query.subscriptions.findFirst({
      where: eq(subscriptions.userId, ctx.user.id),
    });
    return sub ?? null;
  }),

  createCheckoutSession: protectedProcedure
    .input(wrap(CreateCheckoutSessionSchema))
    .mutation(async ({ ctx, input }) => {
      const allowedPrices = [
        process.env.STRIPE_PRICE_BASIC,
        process.env.STRIPE_PRICE_PLUS,
        process.env.STRIPE_PRICE_PREMIUM,
      ].filter(Boolean);

      if (!allowedPrices.includes(input.priceId)) {
        throw new TRPCError({
          code: "BAD_REQUEST",
          message: "Invalid price ID",
        });
      }

      return createCheckoutSession(
        ctx.user.id,
        ctx.user.email,
        input.priceId,
        input.successUrl,
        input.cancelUrl,
      );
    }),

  createPortalSession: protectedProcedure
    .input(wrap(CreatePortalSessionSchema))
    .mutation(async ({ ctx, input }) => {
      const user = ctx.user;
      const stripeCustomerId = user.stripeCustomerId;

      if (!stripeCustomerId) {
        throw new TRPCError({
          code: "NOT_FOUND",
          message: "No Stripe customer found",
        });
      }

      return createPortalSession(stripeCustomerId, input.returnUrl);
    }),

  cancelSubscription: protectedProcedure
    .input(wrap(CancelSubscriptionSchema))
    .mutation(async ({ input }) => {
      return cancelSubscription(input.subscriptionId);
    }),

  reactivateSubscription: protectedProcedure
    .input(wrap(ReactivateSubscriptionSchema))
    .mutation(async ({ input }) => {
      return reactivateSubscription(input.subscriptionId);
    }),

  listInvoices: protectedProcedure
    .input(wrap(ListInvoicesSchema))
    .query(async ({ ctx, input }) => {
      const user = ctx.user;
      const stripeCustomerId = user.stripeCustomerId;

      if (!stripeCustomerId) {
        return { invoices: [], hasMore: false };
      }

      return listInvoices(
        stripeCustomerId,
        parseInt(input.limit ?? "10", 10),
        input.startingAfter,
      );
    }),
});
