import { NextRequest, NextResponse } from "next/server";
import { requireStaffAuth } from "@/lib/staff-auth";
import { prisma } from "@/lib/db";
import {
  createRefund,
  getRefundablePayments,
  RefundReason,
} from "@/lib/stripe";
import { createId } from "@paralleldrive/cuid2";
import { logger } from "@/lib/logger";
import { getDataSource } from "@/lib/data-source";
import { convexQuery, convexMutation } from "@/lib/convex-client";

/**
 * GET /api/staff/dashboard/refunds
 * List all refunds with optional filters
 */
export async function GET(request: NextRequest) {
  try {
    const user = await requireStaffAuth();
    if (!user) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    const { searchParams } = new URL(request.url);
    const status = searchParams.get("status");
    const customerId = searchParams.get("customerId");
    const userId = searchParams.get("userId");
    const limit = parseInt(searchParams.get("limit") || "50");
    const offset = parseInt(searchParams.get("offset") || "0");

    // --- Convex path ---
    if (getDataSource("billing") === "convex") {
      try {
        const result = (await convexQuery(
          (api.billing.queries as any).getRefunds,
          {
            status: status && status !== "all" ? status : undefined,
            customerId: customerId || undefined,
            userId: userId || undefined,
            limit,
            offset,
          },
        )) as any;

        const transformedRefunds = (
          (result?.refunds as Array<Record<string, unknown>>) ?? []
        ).map((refund: any) => ({
          id: refund._id ?? refund.id,
          stripeRefundId: refund.stripeRefundId,
          stripePaymentIntentId: refund.stripePaymentIntentId,
          stripeChargeId: refund.stripeChargeId,
          customerId: refund.customerId,
          userId: refund.userId,
          amount: refund.amount,
          amountFormatted: (refund.amount / 100).toFixed(2),
          currency: refund.currency,
          status: refund.status,
          reason: refund.reason,
          stripeReason: refund.stripeReason,
          staffId: refund.staffId,
          staffNotes: refund.staffNotes,
          customerReason: refund.customerReason,
          failureReason: refund.failureReason,
          createdAt: refund.createdAt
            ? new Date(refund.createdAt).toISOString()
            : null,
          processedAt: refund.processedAt
            ? new Date(refund.processedAt).toISOString()
            : null,
          user: null,
          subscription: null,
        }));

        return NextResponse.json({
          refunds: transformedRefunds,
          total: result?.total ?? 0,
          limit,
          offset,
        });
      } catch (convexErr) {
        console.error(
          "Convex refunds fetch failed, falling back to Prisma:",
          convexErr,
        );
      }
    }

    // --- Prisma path ---
    const where: any = {};

    if (status && status !== "all") {
      where.status = status;
    }

    if (customerId) {
      where.customerId = customerId;
    }

    if (userId) {
      where.userId = userId;
    }

    const [refunds, total] = await Promise.all([
      prisma.refunds.findMany({
        where,
        orderBy: { createdAt: "desc" },
        take: limit,
        skip: offset,
        include: {
          users: {
            select: {
              id: true,
              email: true,
              name: true,
              companyName: true,
            },
          },
          subscriptions: {
            select: {
              id: true,
              tierId: true,
              status: true,
            },
          },
        },
      }),
      prisma.refunds.count({ where }),
    ]);

    // Transform for frontend
    const transformedRefunds = refunds.map((refund) => ({
      id: refund.id,
      stripeRefundId: refund.stripeRefundId,
      stripePaymentIntentId: refund.stripePaymentIntentId,
      stripeChargeId: refund.stripeChargeId,
      customerId: refund.customerId,
      userId: refund.userId,
      amount: refund.amount,
      amountFormatted: (refund.amount / 100).toFixed(2),
      currency: refund.currency,
      status: refund.status,
      reason: refund.reason,
      stripeReason: refund.stripeReason,
      staffId: refund.staffId,
      staffNotes: refund.staffNotes,
      customerReason: refund.customerReason,
      failureReason: refund.failureReason,
      createdAt: refund.createdAt.toISOString(),
      processedAt: refund.processedAt?.toISOString() || null,
      user: refund.users
        ? {
            id: refund.users.id,
            email: refund.users.email,
            name: refund.users.name,
            companyName: refund.users.companyName,
          }
        : null,
      subscription: refund.subscriptions
        ? {
            id: refund.subscriptions.id,
            tierId: refund.subscriptions.tierId,
            status: refund.subscriptions.status,
          }
        : null,
    }));

    return NextResponse.json({
      refunds: transformedRefunds,
      total,
      limit,
      offset,
    });
  } catch (error) {
    logger.error("Failed to fetch refunds:", { error });
    return NextResponse.json(
      { error: "Failed to fetch refunds" },
      { status: 500 },
    );
  }
}

/**
 * POST /api/staff/dashboard/refunds
 * Create a new refund
 */
export async function POST(request: NextRequest) {
  try {
    const user = await requireStaffAuth();
    if (!user) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    // Only ADMIN or SUPER_ADMIN can process refunds
    if (user.role !== "ADMIN" && user.role !== "SUPER_ADMIN") {
      return NextResponse.json(
        { error: "Insufficient permissions to process refunds" },
        { status: 403 },
      );
    }

    const body = await request.json();
    const {
      paymentIntentId,
      chargeId,
      amount, // In cents, optional for full refund
      reason,
      customerReason,
      staffNotes,
      customerId,
      userId,
      subscriptionId,
    } = body;

    // Validate required fields
    if (!paymentIntentId && !chargeId) {
      return NextResponse.json(
        { error: "Either paymentIntentId or chargeId is required" },
        { status: 400 },
      );
    }

    if (!customerId) {
      return NextResponse.json(
        { error: "customerId is required" },
        { status: 400 },
      );
    }

    // Validate reason if provided
    const validReasons: RefundReason[] = [
      "requested_by_customer",
      "duplicate",
      "fraudulent",
    ];
    if (reason && !validReasons.includes(reason)) {
      return NextResponse.json(
        {
          error:
            "Invalid refund reason. Must be: requested_by_customer, duplicate, or fraudulent",
        },
        { status: 400 },
      );
    }

    // --- Convex path for DB save (Stripe API call stays as-is) ---
    const useConvexBilling = getDataSource("billing") === "convex";

    // Create refund in Stripe
    const stripeRefund = await createRefund({
      paymentIntentId,
      chargeId,
      amount,
      reason: reason as RefundReason,
      metadata: {
        staff_id: user.id,
        staff_name: user.name,
        customer_reason: customerReason || "",
      },
    });

    // Generate local ID
    const refundId = createId();

    // Save to Convex if enabled, otherwise save to both databases
    if (useConvexBilling) {
      try {
        await convexMutation("billing/mutations:processRefund", {
          stripeRefundId: stripeRefund.id,
          stripePaymentIntentId: paymentIntentId || undefined,
          customerId,
          userId: userId || undefined,
          amount: stripeRefund.amount,
          currency: stripeRefund.currency,
          reason: reason || undefined,
        });

        // Record billing history in Convex
        await convexMutation("billing/mutations:recordPayment", {
          customerId,
          subscriptionId: subscriptionId || undefined,
          event: "refund_created",
          amount: -stripeRefund.amount,
          currency: stripeRefund.currency,
          metadata: {
            refund_id: stripeRefund.id,
            reason: reason || "not_specified",
            staff_id: user.id,
            staff_name: user.name,
          },
        });

        logger.info("Refund created via Convex", {
          stripeRefundId: stripeRefund.id,
          amount: stripeRefund.amount,
          staffId: user.id,
        });

        return NextResponse.json({
          success: true,
          refund: {
            id: refundId,
            stripeRefundId: stripeRefund.id,
            amount: stripeRefund.amount,
            amountFormatted: (stripeRefund.amount / 100).toFixed(2),
            currency: stripeRefund.currency,
            status: stripeRefund.status,
            reason: reason || null,
            createdAt: new Date().toISOString(),
          },
        });
      } catch (convexErr) {
        console.error(
          "Convex refund save failed, falling back to Prisma:",
          convexErr,
        );
      }
    }

    // Save to both databases

    // Create billing history entry
    const billingHistoryId = createId();

    logger.info("Refund created successfully", {
      refundId: savedRefund.id,
      stripeRefundId: stripeRefund.id,
      amount: stripeRefund.amount,
      staffId: user.id,
    });

    return NextResponse.json({
      success: true,
      refund: {
        id: savedRefund.id,
        stripeRefundId: stripeRefund.id,
        amount: stripeRefund.amount,
        amountFormatted: (stripeRefund.amount / 100).toFixed(2),
        currency: stripeRefund.currency,
        status: stripeRefund.status,
        reason: reason || null,
        createdAt: savedRefund.createdAt.toISOString(),
      },
    });
  } catch (error: any) {
    logger.error("Failed to create refund:", { error: error.message });

    // Handle Stripe-specific errors
    if (error.type === "StripeInvalidRequestError") {
      return NextResponse.json(
        { error: error.message || "Invalid refund request" },
        { status: 400 },
      );
    }

    return NextResponse.json(
      { error: "Failed to create refund" },
      { status: 500 },
    );
  }
}
