/**
 * Stripe Webhook Handler
 *
 * Handles Stripe webhook events for subscription management
 * This route processes:
 * - Subscription creation/updates/cancellations
 * - Payment success/failure
 * - Usage metering for overage billing
 */

import { type ActionFunctionArgs , json } from "@remix-run/node";
import Stripe from "stripe";
import { prisma } from "~/db.server";
import { BILLING_CONFIG, getPlanConfig } from "~/config/billing.server";
import { logger } from "~/services/logger.service";
import type { PlanType } from "@prisma/client";

// Initialize Stripe
const stripe = BILLING_CONFIG.stripe.secretKey
  ? new Stripe(BILLING_CONFIG.stripe.secretKey)
  : null;

/**
 * Verify Stripe webhook signature
 */
function verifyStripeSignature(
  payload: string,
  signature: string,
): Stripe.Event {
  if (!stripe || !BILLING_CONFIG.stripe.webhookSecret) {
    throw new Error("Stripe not configured");
  }

  try {
    return stripe.webhooks.constructEvent(
      payload,
      signature,
      BILLING_CONFIG.stripe.webhookSecret,
    );
  } catch (err) {
    throw new Error(
      `Webhook signature verification failed: ${err instanceof Error ? err.message : "Unknown error"}`,
    );
  }
}

/**
 * Handle customer.subscription.created event
 */
async function handleSubscriptionCreated(subscription: any) {
  logger.info("Handling subscription.created", {
    subscriptionId: subscription.id,
  });

  const customerId = subscription.customer as string;
  const priceId = subscription.items.data[0]?.price.id;

  // Determine plan type from price ID
  let planType: PlanType = "FREE";
  if (priceId === BILLING_CONFIG.plans.pro.stripePriceId) {
    planType = "PRO";
  } else if (priceId === BILLING_CONFIG.plans.max.stripePriceId) {
    planType = "MAX";
  }

  const planConfig = getPlanConfig(planType);

  // Find or create subscription record
  const existingSubscription = await prisma.subscription.findUnique({
    where: { stripeCustomerId: customerId },
  });

  if (existingSubscription) {
    // Update existing subscription
    await prisma.subscription.update({
      where: { id: existingSubscription.id },
      data: {
        stripeSubscriptionId: subscription.id,
        stripePriceId: priceId,
        stripeCurrentPeriodEnd: new Date(
          subscription.current_period_end * 1000,
        ),
        planType,
        status: subscription.status === "active" ? "ACTIVE" : "TRIALING",
        monthlyCredits: planConfig.monthlyCredits,
        enableUsageBilling: planConfig.enableOverage,
        usagePricePerCredit: planConfig.enableOverage
          ? planConfig.overagePrice
          : null,
        currentPeriodStart: new Date(subscription.current_period_start * 1000),
        currentPeriodEnd: new Date(subscription.current_period_end * 1000),
      },
    });

    // Reset user credits
    const workspace = await prisma.workspace.findUnique({
      where: { id: existingSubscription.workspaceId },
      include: { user: { include: { UserUsage: true } } },
    });

    if (workspace?.user?.UserUsage) {
      await prisma.userUsage.update({
        where: { id: workspace.user.UserUsage.id },
        data: {
          availableCredits: planConfig.monthlyCredits,
          usedCredits: 0,
          overageCredits: 0,
          lastResetAt: new Date(),
          nextResetAt: new Date(subscription.current_period_end * 1000),
        },
      });
    }
  }
}

/**
 * Handle customer.subscription.updated event
 */
async function handleSubscriptionUpdated(subscription: any) {
  logger.info("Handling subscription.updated", {
    subscriptionId: subscription.id,
  });

  const priceId = subscription.items.data[0]?.price.id;

  // Determine plan type from price ID
  let planType: PlanType = "FREE";
  if (priceId === BILLING_CONFIG.plans.pro.stripePriceId) {
    planType = "PRO";
  } else if (priceId === BILLING_CONFIG.plans.max.stripePriceId) {
    planType = "MAX";
  }

  const planConfig = getPlanConfig(planType);

  // Update subscription
  const existingSubscription = await prisma.subscription.findUnique({
    where: { stripeSubscriptionId: subscription.id },
  });

  if (existingSubscription) {
    // Determine status - if cancel_at_period_end is true, keep as CANCELED
    let subscriptionStatus;
    if (subscription.cancel_at_period_end) {
      subscriptionStatus = "CANCELED";
    } else if (subscription.status === "active") {
      subscriptionStatus = "ACTIVE";
    } else if (subscription.status === "canceled") {
      subscriptionStatus = "CANCELED";
    } else if (subscription.status === "past_due") {
      subscriptionStatus = "PAST_DUE";
    } else if (subscription.status === "trialing") {
      subscriptionStatus = "TRIALING";
    } else if (subscription.status === "paused") {
      subscriptionStatus = "PAUSED";
    } else {
      subscriptionStatus = "ACTIVE";
    }

    await prisma.subscription.update({
      where: { id: existingSubscription.id },
      data: {
        stripePriceId: priceId,
        stripeCurrentPeriodEnd: new Date(
          subscription.current_period_end * 1000,
        ),
        planType,
        status: subscriptionStatus,
        monthlyCredits: planConfig.monthlyCredits,
        enableUsageBilling: planConfig.enableOverage,
        usagePricePerCredit: planConfig.enableOverage
          ? planConfig.overagePrice
          : null,
        currentPeriodStart: new Date(subscription.current_period_start * 1000),
        currentPeriodEnd: new Date(subscription.current_period_end * 1000),
      },
    });

    // If plan changed, reset credits immediately
    if (existingSubscription.planType !== planType) {
      const workspace = await prisma.workspace.findUnique({
        where: { id: existingSubscription.workspaceId },
        include: { user: { include: { UserUsage: true } } },
      });

      if (workspace?.user?.UserUsage) {
        await prisma.userUsage.update({
          where: { id: workspace.user.UserUsage.id },
          data: {
            availableCredits: planConfig.monthlyCredits,
            usedCredits: 0,
            overageCredits: 0,
            lastResetAt: new Date(),
            nextResetAt: new Date(subscription.current_period_end * 1000),
          },
        });
      }
    }
  }
}

/**
 * Handle customer.subscription.deleted event
 */
async function handleSubscriptionDeleted(subscription: Stripe.Subscription) {
  logger.info("Handling subscription.deleted", {
    subscriptionId: subscription.id,
  });

  const existingSubscription = await prisma.subscription.findUnique({
    where: { stripeSubscriptionId: subscription.id },
  });

  if (existingSubscription) {
    // Downgrade to FREE plan
    const freeConfig = getPlanConfig("FREE");

    await prisma.subscription.update({
      where: { id: existingSubscription.id },
      data: {
        planType: "FREE",
        status: "ACTIVE", // FREE plan is now active
        monthlyCredits: freeConfig.monthlyCredits,
        enableUsageBilling: false,
        usagePricePerCredit: null,
        stripeSubscriptionId: null,
        stripePriceId: null,
        overageCreditsUsed: 0,
        overageAmount: 0,
      },
    });

    // Reset to free tier credits
    const workspace = await prisma.workspace.findUnique({
      where: { id: existingSubscription.workspaceId },
      include: { user: { include: { UserUsage: true } } },
    });

    if (workspace?.user?.UserUsage) {
      await prisma.userUsage.update({
        where: { id: workspace.user.UserUsage.id },
        data: {
          availableCredits: freeConfig.monthlyCredits,
          usedCredits: 0,
          overageCredits: 0,
        },
      });
    }
  }
}

/**
 * Handle invoice.payment_succeeded event
 */
async function handleInvoicePaymentSucceeded(invoice: Stripe.Invoice) {
  logger.info("Handling invoice.payment_succeeded", { invoiceId: invoice.id });

  const subscriptionId = (invoice as any).subscription as string;
  const tax = (invoice as any).tax || 0;

  if (subscriptionId) {
    const subscription = await prisma.subscription.findUnique({
      where: { stripeSubscriptionId: subscriptionId },
    });

    if (subscription) {
      // Create billing history record
      await prisma.billingHistory.create({
        data: {
          subscriptionId: subscription.id,
          periodStart: subscription.currentPeriodStart,
          periodEnd: subscription.currentPeriodEnd,
          monthlyCreditsAllocated: subscription.monthlyCredits,
          creditsUsed: 0, // Will be updated from UserUsage
          overageCreditsUsed: subscription.overageCreditsUsed,
          subscriptionAmount: (invoice.amount_paid - (tax || 0)) / 100,
          usageAmount: subscription.overageAmount,
          totalAmount: invoice.amount_paid / 100,
          stripeInvoiceId: invoice.id,
          stripePaymentStatus: invoice.status || "paid",
        },
      });

      // Reset overage tracking after successful payment
      await prisma.subscription.update({
        where: { id: subscription.id },
        data: {
          overageCreditsUsed: 0,
          overageAmount: 0,
        },
      });
    }
  }
}

/**
 * Handle invoice.payment_failed event
 */
async function handleInvoicePaymentFailed(invoice: Stripe.Invoice) {
  logger.error("Handling invoice.payment_failed", { invoiceId: invoice.id });

  const subscriptionId = (invoice as any).subscription as string;

  if (subscriptionId) {
    const subscription = await prisma.subscription.findUnique({
      where: { stripeSubscriptionId: subscriptionId },
    });

    if (subscription) {
      await prisma.subscription.update({
        where: { id: subscription.id },
        data: {
          status: "PAST_DUE",
        },
      });

      // TODO: Send email notification to user about failed payment
    }
  }
}

/**
 * Main webhook handler
 */
export async function action({ request }: ActionFunctionArgs) {
  // Check if billing is enabled
  if (!BILLING_CONFIG.enabled) {
    return json({ error: "Billing is not enabled" }, { status: 400 });
  }

  if (!stripe) {
    return json({ error: "Stripe not configured" }, { status: 500 });
  }

  const signature = request.headers.get("stripe-signature");
  if (!signature) {
    return json({ error: "Missing stripe-signature header" }, { status: 400 });
  }

  const payload = await request.text();

  try {
    const event = verifyStripeSignature(payload, signature);

    logger.info("Received Stripe webhook", {
      type: event.type,
      id: event.id,
    });

    // Handle different event types
    switch (event.type) {
      case "customer.subscription.created":
        await handleSubscriptionCreated(
          event.data.object as Stripe.Subscription,
        );
        break;

      case "customer.subscription.updated":
        await handleSubscriptionUpdated(
          event.data.object as Stripe.Subscription,
        );
        break;

      case "customer.subscription.deleted":
        await handleSubscriptionDeleted(
          event.data.object as Stripe.Subscription,
        );
        break;

      case "invoice.payment_succeeded":
        await handleInvoicePaymentSucceeded(
          event.data.object as Stripe.Invoice,
        );
        break;

      case "invoice.payment_failed":
        await handleInvoicePaymentFailed(event.data.object as Stripe.Invoice);
        break;

      default:
        logger.info(`Unhandled webhook event type: ${event.type}`);
    }

    return json({ received: true });
  } catch (err) {
    logger.error("Webhook handler error", { error: err });
    return json(
      { error: err instanceof Error ? err.message : "Webhook handler failed" },
      { status: 400 },
    );
  }
}
