/**
 * Integration Test: Billing API Endpoints
 * Comprehensive tests for subscription and billing endpoints
 *
 * Prevents regression by testing:
 * 1. /api/subscription/details returns correct data structure
 * 2. /api/user/package-status returns subscription correctly
 * 3. Relation names are used correctly
 * 4. Trial subscriptions are detected
 * 5. Billing history is included
 */

import { prisma } from "@/lib/db";
import { createId } from "@paralleldrive/cuid2";

// Requires live database - skip in unit test environment
describe.skip("Billing API Endpoints Integration", () => {
  let testUserId: string;
  let testUserEmail: string;
  let testSubscriptionId: string;
  let testStripeSubscriptionId: string;

  beforeAll(async () => {
    // Create test user
    const userId = createId();
    const email = `billing-api-test-${Date.now()}@example.com`;

    await prisma.users.create({
      data: {
        id: userId,
        email,
        name: "Billing API Test User",
        password: "hashed_password",
        role: "CUSTOMER",
        onboardingComplete: true,
        selectedPackage: "tier2",
      },
    });

    testUserId = userId;
    testUserEmail = email;
    testStripeSubscriptionId = `sub_test_${Date.now()}`;

    // Create test subscription (trialing status)
    const subId = createId();
    await prisma.subscriptions.create({
      data: {
        id: subId,
        userId: testUserId,
        stripeCustomerId: `cus_test_${Date.now()}`,
        stripeSubscriptionId: testStripeSubscriptionId,
        stripePriceId: "price_test",
        tierId: "tier2",
        status: "trialing",
        billingPeriod: "monthly",
        currentPeriodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
        trialEndsAt: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000),
        setupFeePaid: true,
        setupFeeAmount: 91900,
        setupFeePaidAt: new Date(),
        cardBrand: "visa",
        cardLastFour: "4242",
        paymentMethodId: "pm_test",
        updatedAt: new Date(),
      },
    });

    testSubscriptionId = subId;

    // Create billing history
    await prisma.billing_history.create({
      data: {
        id: createId(),
        userId: testUserId,
        subscriptionId: testSubscriptionId,
        event: "checkout_completed",
        amount: 91900,
        currency: "qar",
        metadata: { payment_type: "setup_fee" },
      },
    });
  });

  afterAll(async () => {
    await prisma.billing_history.deleteMany({ where: { userId: testUserId } });
    await prisma.subscriptions.deleteMany({ where: { userId: testUserId } });
    await prisma.users.delete({ where: { id: testUserId } });
    await prisma.$disconnect();
  });

  describe("/api/subscription/details - Query Structure", () => {
    it("should find subscription using correct relation names", async () => {
      const subscription = await prisma.subscriptions.findFirst({
        where: {
          users: {
            // ✅ Must be "users" not "user"
            email: testUserEmail,
          },
          status: {
            in: ["active", "trialing", "past_due"],
          },
        },
        include: {
          billing_history: {
            // ✅ Must be "billing_history" not "billingHistory"
            orderBy: {
              createdAt: "desc",
            },
            take: 20,
          },
          users: true, // ✅ Must be "users" not "user"
        },
      });

      expect(subscription).not.toBeNull();
      expect(subscription?.id).toBe(testSubscriptionId);
      expect(subscription?.tierId).toBe("tier2");
      expect(subscription?.status).toBe("trialing");
      expect(subscription?.users).toBeDefined();
      expect(subscription?.billing_history).toBeDefined();
    });

    it("should return complete subscription data structure", async () => {
      const subscription = await prisma.subscriptions.findFirst({
        where: {
          users: { email: testUserEmail },
          status: { in: ["active", "trialing", "past_due"] },
        },
        include: {
          billing_history: { orderBy: { createdAt: "desc" }, take: 20 },
          users: true,
        },
      });

      // Verify all expected fields exist
      expect(subscription).toMatchObject({
        id: expect.any(String),
        userId: testUserId,
        tierId: "tier2",
        status: "trialing",
        billingPeriod: "monthly",
        setupFeePaid: true,
        setupFeeAmount: 91900,
        stripeCustomerId: expect.stringContaining("cus_"),
        stripeSubscriptionId: expect.stringContaining("sub_"),
        cardBrand: "visa",
        cardLastFour: "4242",
      });

      // Verify relations
      expect(subscription?.users.email).toBe(testUserEmail);
      expect(subscription?.billing_history.length).toBeGreaterThan(0);
    });

    it("should format response correctly for API", async () => {
      const subscription = await prisma.subscriptions.findFirst({
        where: {
          users: { email: testUserEmail },
          status: { in: ["active", "trialing", "past_due"] },
        },
        include: {
          billing_history: { orderBy: { createdAt: "desc" }, take: 20 },
          users: true,
        },
      });

      // Simulate API response formatting
      const response = {
        subscription: {
          id: subscription!.id,
          tierId: subscription!.tierId,
          status: subscription!.status,
          billingPeriod: subscription!.billingPeriod,
          currentPeriodEnd: subscription!.currentPeriodEnd,
          trialEndsAt: subscription!.trialEndsAt,
          setupFeePaid: subscription!.setupFeePaid,
          setupFeeAmount: subscription!.setupFeeAmount,
          paymentMethod:
            subscription!.cardBrand && subscription!.cardLastFour
              ? {
                  brand: subscription!.cardBrand,
                  lastFour: subscription!.cardLastFour,
                  id: subscription!.paymentMethodId,
                }
              : null,
        },
        user: {
          id: subscription!.users.id, // ✅ Must use "users" not "user"
          email: subscription!.users.email,
          name: subscription!.users.name,
          companyName: subscription!.users.companyName,
        },
        billingHistory: subscription!.billing_history.map((item) => ({
          // ✅ Must use "billing_history"
          id: item.id,
          event: item.event,
          amount: item.amount,
          currency: item.currency,
        })),
      };

      expect(response.subscription.tierId).toBe("tier2");
      expect(response.subscription.status).toBe("trialing");
      expect(response.subscription.setupFeePaid).toBe(true);
      expect(response.user.email).toBe(testUserEmail);
      expect(response.billingHistory.length).toBeGreaterThan(0);
    });
  });

  describe("/api/user/package-status - Query Structure", () => {
    it("should find user with subscriptions using correct relation", async () => {
      const user = await prisma.users.findUnique({
        where: { email: testUserEmail },
        include: {
          subscriptions: {
            where: {
              status: { in: ["active", "trialing", "past_due"] },
            },
            orderBy: { createdAt: "desc" },
            take: 1,
            include: {
              billing_history: {
                // ✅ Must be "billing_history"
                orderBy: { createdAt: "desc" },
                take: 20,
              },
            },
          },
        },
      });

      expect(user).not.toBeNull();
      expect(user?.subscriptions.length).toBeGreaterThan(0);
      expect(user?.subscriptions[0].billing_history).toBeDefined();
    });
  });

  describe("Trial Subscription Detection", () => {
    it("should detect trialing subscriptions correctly", async () => {
      const subscription = await prisma.subscriptions.findFirst({
        where: {
          users: { email: testUserEmail },
          status: { in: ["active", "trialing", "past_due"] }, // ✅ Includes trialing
        },
      });

      expect(subscription).not.toBeNull();
      expect(subscription?.status).toBe("trialing");
    });

    it("should return trialing subscription in package-status query", async () => {
      const user = await prisma.users.findUnique({
        where: { email: testUserEmail },
        include: {
          subscriptions: {
            where: {
              status: { in: ["active", "trialing", "past_due"] },
            },
          },
        },
      });

      const hasActiveSubscription = user!.subscriptions.length > 0;
      const subscription = user!.subscriptions[0];

      expect(hasActiveSubscription).toBe(true);
      expect(subscription.status).toBe("trialing");
      expect(subscription.setupFeePaid).toBe(true);
    });
  });

  describe("Setup Fee Validation", () => {
    it("should correctly retrieve setup fee information", async () => {
      const subscription = await prisma.subscriptions.findFirst({
        where: {
          users: { email: testUserEmail },
          status: { in: ["active", "trialing", "past_due"] },
        },
      });

      expect(subscription?.setupFeePaid).toBe(true);
      expect(subscription?.setupFeeAmount).toBe(91900);
      expect(subscription?.setupFeePaidAt).toBeDefined();
    });
  });

  describe("Payment Method Information", () => {
    it("should retrieve payment method details correctly", async () => {
      const subscription = await prisma.subscriptions.findFirst({
        where: {
          users: { email: testUserEmail },
          status: { in: ["active", "trialing", "past_due"] },
        },
      });

      expect(subscription?.cardBrand).toBe("visa");
      expect(subscription?.cardLastFour).toBe("4242");
      expect(subscription?.paymentMethodId).toBeTruthy();
    });
  });
});

/**
 * Helper function to extract a model definition from Prisma schema
 */
function extractModel(schemaContent: string, modelName: string): string {
  const lines = schemaContent.split("\n");
  const modelStartIndex = lines.findIndex((line) =>
    line.trim().startsWith(`model ${modelName}`),
  );

  if (modelStartIndex === -1) {
    throw new Error(`Model ${modelName} not found in schema`);
  }

  let braceCount = 0;
  let modelContent = "";
  let started = false;

  for (let i = modelStartIndex; i < lines.length; i++) {
    const line = lines[i];
    modelContent += line + "\n";

    for (const char of line) {
      if (char === "{") {
        braceCount++;
        started = true;
      } else if (char === "}") {
        braceCount--;
      }
    }

    if (started && braceCount === 0) {
      break;
    }
  }

  return modelContent;
}
