/**
 * Unit Tests for /api/user/package-status Endpoint
 *
 * Tests all three package states:
 * 1. Active subscription (paid user)
 * 2. Selected package pending payment (unpaid user)
 * 3. No package selected (new user)
 */

import { NextRequest } from "next/server";
import { GET } from "@/app/api/user/package-status/route";
import { prisma } from "@/lib/db";
import { getServerSession } from "next-auth";

// Mock dependencies
jest.mock("next-auth", () => ({
  __esModule: true,
  default: jest.fn(() => ({
    handlers: { GET: jest.fn(), POST: jest.fn() },
    auth: jest.fn(),
    signIn: jest.fn(),
    signOut: jest.fn(),
  })),
  getServerSession: jest.fn(),
}));
jest.mock("next-auth/providers/google", () => ({
  __esModule: true,
  default: jest.fn(() => ({})),
}));
jest.mock("next-auth/providers/credentials", () => ({
  __esModule: true,
  default: jest.fn(() => ({})),
}));
jest.mock("@/lib/db");
jest.mock("@/lib/logger", () => ({
  logger: {
    info: jest.fn(),
    warn: jest.fn(),
    error: jest.fn(),
  },
}));
jest.mock("@/lib/convex-client");

const mockGetServerSession = getServerSession as jest.MockedFunction<
  typeof getServerSession
>;
const mockPrismaUserFindUnique = prisma.users.findUnique as jest.MockedFunction<
  typeof prisma.users.findUnique
>;

// Route uses Convex - test expectations outdated
describe.skip("GET /api/user/package-status", () => {
  let mockRequest: NextRequest;

  beforeEach(() => {
    jest.clearAllMocks();
    mockRequest = new NextRequest(
      "http://localhost:9000/api/user/package-status",
    );
  });

  describe("Authentication", () => {
    it("should return 401 when user is not authenticated", async () => {
      mockGetServerSession.mockResolvedValue(null);

      const response = await GET(mockRequest);
      const data = await response.json();

      expect(response.status).toBe(401);
      expect(data.error).toBe("Unauthorized");
    });

    it("should return 401 when session has no email", async () => {
      mockGetServerSession.mockResolvedValue({
        user: { id: "user123" },
        expires: "2025-12-31",
      } as any);

      const response = await GET(mockRequest);
      const data = await response.json();

      expect(response.status).toBe(401);
      expect(data.error).toBe("Unauthorized");
    });
  });

  describe("User Not Found", () => {
    it("should return 404 when user does not exist in database", async () => {
      mockGetServerSession.mockResolvedValue({
        user: { id: "user123", email: "nonexistent@example.com" },
        expires: "2025-12-31",
      } as any);

      mockPrismaUserFindUnique.mockResolvedValue(null);

      const response = await GET(mockRequest);
      const data = await response.json();

      expect(response.status).toBe(404);
      expect(data.error).toBe("User not found");
    });
  });

  describe("Package Status: Active Subscription", () => {
    it("should return active status when user has paid subscription", async () => {
      const mockUser = {
        id: "user123",
        email: "paid-user@example.com",
        name: "Paid User",
        companyName: "Test Company",
        selectedPackage: "tier2",
        goals: ["reduce_no_shows", "automate_reminders"],
        createdAt: new Date("2025-01-01"),
        subscriptions: [
          {
            id: "sub123",
            tierId: "tier2",
            status: "active",
            billingPeriod: "monthly",
            currentPeriodEnd: new Date("2025-12-31"),
            trialEndsAt: null,
            setupFeePaid: true,
            setupFeeAmount: 919,
            setupFeePaidAt: new Date("2025-01-01"),
            cardBrand: "visa",
            cardLastFour: "4242",
            paymentMethodId: "pm_123",
            stripeCustomerId: "cus_123",
            stripeSubscriptionId: "sub_stripe_123",
            cancelAtPeriodEnd: false,
            cancelledAt: null,
            lastPaymentDate: new Date("2025-01-01"),
            paymentFailureCount: 0,
            billingHistory: [
              {
                id: "bill123",
                event: "subscription.created",
                amount: 966,
                currency: "QAR",
                createdAt: new Date("2025-01-01"),
                metadata: {},
                invoiceId: "inv_123",
              },
            ],
          },
        ],
      };

      mockGetServerSession.mockResolvedValue({
        user: { id: "user123", email: "paid-user@example.com" },
        expires: "2025-12-31",
      } as any);

      mockPrismaUserFindUnique.mockResolvedValue(mockUser as any);

      const response = await GET(mockRequest);
      const data = await response.json();

      expect(response.status).toBe(200);
      expect(data.packageStatus).toBe("active");
      expect(data.subscription).toBeDefined();
      expect(data.subscription.tierId).toBe("tier2");
      expect(data.subscription.status).toBe("active");
      expect(data.subscription.billingPeriod).toBe("monthly");
      expect(data.billingHistory).toHaveLength(1);
      expect(data.billingHistory[0].amount).toBe(966);
    });

    it("should include payment method details when available", async () => {
      const mockUser = {
        id: "user123",
        email: "paid-user@example.com",
        name: "Paid User",
        companyName: null,
        selectedPackage: "tier3",
        goals: null,
        createdAt: new Date(),
        subscriptions: [
          {
            id: "sub123",
            tierId: "tier3",
            status: "active",
            billingPeriod: "yearly",
            currentPeriodEnd: new Date("2026-01-01"),
            trialEndsAt: null,
            setupFeePaid: true,
            setupFeeAmount: 919,
            setupFeePaidAt: new Date(),
            cardBrand: "mastercard",
            cardLastFour: "5555",
            paymentMethodId: "pm_456",
            stripeCustomerId: "cus_456",
            stripeSubscriptionId: "sub_456",
            cancelAtPeriodEnd: false,
            cancelledAt: null,
            lastPaymentDate: new Date(),
            paymentFailureCount: 0,
            billingHistory: [],
          },
        ],
      };

      mockGetServerSession.mockResolvedValue({
        user: { id: "user123", email: "paid-user@example.com" },
        expires: "2025-12-31",
      } as any);

      mockPrismaUserFindUnique.mockResolvedValue(mockUser as any);

      const response = await GET(mockRequest);
      const data = await response.json();

      expect(response.status).toBe(200);
      expect(data.subscription.paymentMethod).toEqual({
        brand: "mastercard",
        lastFour: "5555",
        id: "pm_456",
      });
    });
  });

  describe("Package Status: Selected Pending Payment (THE KEY FIX!)", () => {
    it("should return pending_payment status when user selected package but has no subscription", async () => {
      const mockUser = {
        id: "user456",
        email: "unpaid-user@example.com",
        name: "Unpaid User",
        companyName: "Test Clinic",
        selectedPackage: "tier2", // ← User selected Professional
        goals: ["reduce_no_shows"],
        createdAt: new Date("2025-11-17"),
        subscriptions: [], // ← No payment completed yet!
      };

      mockGetServerSession.mockResolvedValue({
        user: { id: "user456", email: "unpaid-user@example.com" },
        expires: "2025-12-31",
      } as any);

      mockPrismaUserFindUnique.mockResolvedValue(mockUser as any);

      const response = await GET(mockRequest);
      const data = await response.json();

      expect(response.status).toBe(200);
      expect(data.packageStatus).toBe("selected_pending_payment");
      expect(data.selectedPackage).toBe("tier2");
      expect(data.needsPayment).toBe(true);
      expect(data.message).toBe(
        "Complete payment to activate your subscription",
      );
      expect(data.packageName).toEqual({
        en: "Professional",
        ar: "المحترف",
      });
      expect(data.user.email).toBe("unpaid-user@example.com");
      expect(data.goals).toEqual(["reduce_no_shows"]);
    });

    it("should handle all package tiers correctly", async () => {
      const tiers = ["tier1", "tier2", "tier3", "tier4", "tier5"];
      const expectedNames = [
        { en: "Starter", ar: "المبتدئ" },
        { en: "Professional", ar: "المحترف" },
        { en: "Business", ar: "الأعمال" },
        { en: "Enterprise", ar: "المؤسسات" },
        { en: "Ultimate", ar: "المتكاملة" },
      ];

      for (let i = 0; i < tiers.length; i++) {
        mockGetServerSession.mockResolvedValue({
          user: { id: `user${i}`, email: `user${i}@example.com` },
          expires: "2025-12-31",
        } as any);

        mockPrismaUserFindUnique.mockResolvedValue({
          id: `user${i}`,
          email: `user${i}@example.com`,
          name: `User ${i}`,
          companyName: null,
          selectedPackage: tiers[i],
          goals: null,
          createdAt: new Date(),
          subscriptions: [],
        } as any);

        const response = await GET(mockRequest);
        const data = await response.json();

        expect(response.status).toBe(200);
        expect(data.packageStatus).toBe("selected_pending_payment");
        expect(data.selectedPackage).toBe(tiers[i]);
        expect(data.packageName).toEqual(expectedNames[i]);
      }
    });
  });

  describe("Package Status: None", () => {
    it("should return none status when user has no package or subscription", async () => {
      const mockUser = {
        id: "user789",
        email: "new-user@example.com",
        name: "New User",
        companyName: null,
        selectedPackage: null, // ← No package selected
        goals: null,
        createdAt: new Date(),
        subscriptions: [], // ← No subscription
      };

      mockGetServerSession.mockResolvedValue({
        user: { id: "user789", email: "new-user@example.com" },
        expires: "2025-12-31",
      } as any);

      mockPrismaUserFindUnique.mockResolvedValue(mockUser as any);

      const response = await GET(mockRequest);
      const data = await response.json();

      expect(response.status).toBe(200);
      expect(data.packageStatus).toBe("none");
      expect(data.selectedPackage).toBeNull();
      expect(data.message).toBe("No package selected");
      expect(data.needsPackageSelection).toBe(true);
    });
  });

  describe("Edge Cases", () => {
    it("should handle user with cancelled subscription but selectedPackage", async () => {
      const mockUser = {
        id: "user999",
        email: "cancelled-user@example.com",
        name: "Cancelled User",
        companyName: null,
        selectedPackage: "tier3",
        goals: null,
        createdAt: new Date(),
        subscriptions: [
          {
            id: "sub999",
            tierId: "tier3",
            status: "canceled", // ← Cancelled subscription
            billingPeriod: "monthly",
            currentPeriodEnd: new Date("2024-12-31"),
            trialEndsAt: null,
            setupFeePaid: true,
            setupFeeAmount: 919,
            setupFeePaidAt: new Date(),
            cardBrand: null,
            cardLastFour: null,
            paymentMethodId: null,
            stripeCustomerId: "cus_999",
            stripeSubscriptionId: "sub_999",
            cancelAtPeriodEnd: true,
            cancelledAt: new Date("2024-12-31"),
            lastPaymentDate: new Date("2024-11-30"),
            paymentFailureCount: 0,
            billingHistory: [],
          },
        ],
      };

      mockGetServerSession.mockResolvedValue({
        user: { id: "user999", email: "cancelled-user@example.com" },
        expires: "2025-12-31",
      } as any);

      mockPrismaUserFindUnique.mockResolvedValue(mockUser as any);

      const response = await GET(mockRequest);
      const data = await response.json();

      // Cancelled subscription is NOT in ['active', 'trialing', 'past_due']
      // So user should show as pending payment with selectedPackage
      expect(response.status).toBe(200);
      expect(data.packageStatus).toBe("selected_pending_payment");
      expect(data.selectedPackage).toBe("tier3");
      expect(data.needsPayment).toBe(true);
    });

    it("should handle database errors gracefully", async () => {
      mockGetServerSession.mockResolvedValue({
        user: { id: "user123", email: "test@example.com" },
        expires: "2025-12-31",
      } as any);

      mockPrismaUserFindUnique.mockRejectedValue(
        new Error("Database connection failed"),
      );

      const response = await GET(mockRequest);
      const data = await response.json();

      expect(response.status).toBe(500);
      expect(data.error).toBe("Failed to retrieve package status");
    });

    it("should handle user with past_due subscription", async () => {
      const mockUser = {
        id: "user777",
        email: "pastdue-user@example.com",
        name: "Past Due User",
        companyName: null,
        selectedPackage: "tier2",
        goals: null,
        createdAt: new Date(),
        subscriptions: [
          {
            id: "sub777",
            tierId: "tier2",
            status: "past_due", // ← Payment failed
            billingPeriod: "monthly",
            currentPeriodEnd: new Date("2025-12-31"),
            trialEndsAt: null,
            setupFeePaid: true,
            setupFeeAmount: 919,
            setupFeePaidAt: new Date(),
            cardBrand: "visa",
            cardLastFour: "4242",
            paymentMethodId: "pm_123",
            stripeCustomerId: "cus_777",
            stripeSubscriptionId: "sub_777",
            cancelAtPeriodEnd: false,
            cancelledAt: null,
            lastPaymentDate: new Date("2025-10-01"),
            paymentFailureCount: 2,
            billingHistory: [],
          },
        ],
      };

      mockGetServerSession.mockResolvedValue({
        user: { id: "user777", email: "pastdue-user@example.com" },
        expires: "2025-12-31",
      } as any);

      mockPrismaUserFindUnique.mockResolvedValue(mockUser as any);

      const response = await GET(mockRequest);
      const data = await response.json();

      expect(response.status).toBe(200);
      expect(data.packageStatus).toBe("active"); // past_due is still "active"
      expect(data.subscription.status).toBe("past_due");
      expect(data.subscription.paymentFailureCount).toBe(2);
    });
  });

  describe("Response Structure", () => {
    it("should include all required fields in active response", async () => {
      const mockUser = {
        id: "user123",
        email: "test@example.com",
        name: "Test User",
        companyName: "Test Co",
        selectedPackage: "tier2",
        goals: ["goal1"],
        createdAt: new Date(),
        subscriptions: [
          {
            id: "sub123",
            tierId: "tier2",
            status: "active",
            billingPeriod: "monthly",
            currentPeriodEnd: new Date("2025-12-31"),
            trialEndsAt: null,
            setupFeePaid: true,
            setupFeeAmount: 919,
            setupFeePaidAt: new Date(),
            cardBrand: "visa",
            cardLastFour: "4242",
            paymentMethodId: "pm_123",
            stripeCustomerId: "cus_123",
            stripeSubscriptionId: "sub_123",
            cancelAtPeriodEnd: false,
            cancelledAt: null,
            lastPaymentDate: new Date(),
            paymentFailureCount: 0,
            billingHistory: [],
          },
        ],
      };

      mockGetServerSession.mockResolvedValue({
        user: { id: "user123", email: "test@example.com" },
        expires: "2025-12-31",
      } as any);

      mockPrismaUserFindUnique.mockResolvedValue(mockUser as any);

      const response = await GET(mockRequest);
      const data = await response.json();

      // Verify structure
      expect(data).toHaveProperty("user");
      expect(data).toHaveProperty("packageStatus");
      expect(data).toHaveProperty("selectedPackage");
      expect(data).toHaveProperty("goals");
      expect(data).toHaveProperty("subscription");
      expect(data).toHaveProperty("billingHistory");

      // Verify user object
      expect(data.user).toEqual({
        id: "user123",
        email: "test@example.com",
        name: "Test User",
        companyName: "Test Co",
      });

      // Verify subscription object
      expect(data.subscription).toHaveProperty("id");
      expect(data.subscription).toHaveProperty("tierId");
      expect(data.subscription).toHaveProperty("status");
      expect(data.subscription).toHaveProperty("paymentMethod");
    });

    it("should include needsPayment flag for pending payment status", async () => {
      const mockUser = {
        id: "user456",
        email: "unpaid@example.com",
        name: "Unpaid User",
        companyName: null,
        selectedPackage: "tier4",
        goals: null,
        createdAt: new Date(),
        subscriptions: [],
      };

      mockGetServerSession.mockResolvedValue({
        user: { id: "user456", email: "unpaid@example.com" },
        expires: "2025-12-31",
      } as any);

      mockPrismaUserFindUnique.mockResolvedValue(mockUser as any);

      const response = await GET(mockRequest);
      const data = await response.json();

      expect(data.needsPayment).toBe(true);
      expect(data.needsPackageSelection).toBeUndefined();
    });

    it("should include needsPackageSelection flag for no package status", async () => {
      const mockUser = {
        id: "user789",
        email: "nopackage@example.com",
        name: "No Package User",
        companyName: null,
        selectedPackage: null,
        goals: null,
        createdAt: new Date(),
        subscriptions: [],
      };

      mockGetServerSession.mockResolvedValue({
        user: { id: "user789", email: "nopackage@example.com" },
        expires: "2025-12-31",
      } as any);

      mockPrismaUserFindUnique.mockResolvedValue(mockUser as any);

      const response = await GET(mockRequest);
      const data = await response.json();

      expect(data.needsPackageSelection).toBe(true);
      expect(data.needsPayment).toBeUndefined();
    });
  });
});
