import { describe, it, expect, vi, beforeEach } from "vitest";
import {
	render,
	screen,
	within,
	fireEvent,
	waitFor,
} from "@testing-library/react";
import { AccountDashboardPage } from "../account-dashboard-page";
import { WithKiroAccountApiContext } from "../../../context/account-dashboard-api-context";
import { mockUsageLimitsData } from "../../../hooks/__tests__/mockUsageLimitsData";
import { useUsageLimits } from "../../../hooks/useUsageLimits";
import type {
	AccountDashboardApi,
	ProviderId,
} from "../../../types/account-dashboard-types";

// Mock the useUsageLimits hook
vi.mock("../../../hooks/useUsageLimits");

const mockUseUsageLimits = vi.mocked(useUsageLimits);

// Mock API context
const mockApi: AccountDashboardApi = {
	close: vi.fn(),
	signIn: vi.fn(),
	signOut: vi.fn(),
	executeCommand: vi.fn(),
	getUsageLimits: vi.fn(),
	enableOverages: vi.fn(),
	getPaymentPortalUrl: vi.fn(),
	showProfileSelector: vi.fn(),
	openExternalLink: vi.fn(),
	getCurrentProfile: vi.fn(),
	listAvailableProfiles: vi.fn(),
};

// Helper function to render component with context
const renderWithContext = (api = mockApi) => {
	return render(
		<WithKiroAccountApiContext api={api}>
			<AccountDashboardPage />
		</WithKiroAccountApiContext>,
	);
};

describe("AccountDashboardPage", () => {
	beforeEach(() => {
		vi.clearAllMocks();
	});

	describe("Loading State", () => {
		it("should show loading skeleton when loading", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: null,
				loading: true,
				error: null,
			});

			renderWithContext();

			// Check for loading skeleton elements
			expect(screen.getByTestId("loading-skeleton")).toBeInTheDocument();
		});
	});

	describe("Error States", () => {
		it("should show error message for general errors", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: null,
				loading: false,
				error: {
					message: "Failed to fetch usage limits. Please try again later.",
					statusCode: 500,
					apiError: new Error("Server error"),
				},
			});

			renderWithContext();

			expect(
				screen.getByText(
					"Failed to fetch usage limits. Please try again later.",
				),
			).toBeInTheDocument();
		});

		it("should show empty page for 403 errors", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: null,
				loading: false,
				error: {
					message: "Forbidden",
					statusCode: 403,
					reason: "FEATURE_NOT_SUPPORTED",
					apiError: new Error("Forbidden"),
					isLoggedIn: false,
				},
			});

			renderWithContext();

			// Should not show error message for 403
			expect(screen.queryByText("Forbidden")).not.toBeInTheDocument();
		});
	});

	describe("Sign-in States", () => {
		it("should show sign-in prompt when user is not logged in", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: {
					...mockUsageLimitsData.freeUserLowUsage.data!,
					userInfo: {
						...mockUsageLimitsData.freeUserLowUsage.data!.userInfo,
						isLoggedIn: false,
					},
				},
				loading: false,
				error: null,
			});

			renderWithContext();

			expect(
				screen.getByText("Sign in to view your account"),
			).toBeInTheDocument();
		});
	});

	describe("Free User Scenarios", () => {
		it("should show upgrade plan button for free users", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.freeUserUpgradeTest.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			expect(screen.getByText("Upgrade Plan")).toBeInTheDocument();
			expect(screen.queryByText("Manage Plan")).not.toBeInTheDocument();
		});

		it("should show usage summary for free users with low usage", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.freeUserLowUsage.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			// Check for usage breakdown elements
			expect(screen.getByText("Vibe")).toBeInTheDocument();
			expect(screen.getByText("Spec")).toBeInTheDocument();
			expect(
				screen.getByText("45 used / 100 covered in plan"),
			).toBeInTheDocument();
			expect(
				screen.getByText("120 used / 500 covered in plan"),
			).toBeInTheDocument();
		});

		it("should show warning for free users approaching limits", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.freeUserHighUsage.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			// Check for high usage indicators (92% and 95% usage)
			expect(
				screen.getByText("92 used / 100 covered in plan"),
			).toBeInTheDocument();
			expect(
				screen.getByText("475 used / 500 covered in plan"),
			).toBeInTheDocument();
		});

		it("should not show overage settings for free users", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.freeUserLowUsage.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			// Free users should not see overage settings
			expect(screen.queryByText("Overages")).not.toBeInTheDocument();
		});
	});

	describe("Trial User Scenarios", () => {
		it("should show welcome bonus banner for free trial users", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.freeTrialUser.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			// Should show welcome bonus banner
			expect(screen.getByText("Bonus Credits")).toBeInTheDocument();
			expect(screen.getByText("12 days")).toBeInTheDocument();
			expect(screen.getByText("300 used / 500 total")).toBeInTheDocument();
		});

		it("should show welcome bonus banner for paid trial users", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.activeTrialBillingTest.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			// Should show welcome bonus banner
			expect(screen.getByText("Bonus Credits")).toBeInTheDocument();
			expect(screen.getByText("2 days")).toBeInTheDocument();
			expect(screen.getByText("200 used / 500 total")).toBeInTheDocument();
		});

		it("should show multiple welcome bonus banners for users with multiple trial breakdowns", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.multipleTrialBreakdowns.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			expect(screen.getByText("Bonus Credits")).toBeInTheDocument();

			// Should show SPEC trial breakdown
			expect(screen.getByText("400 used / 600 total")).toBeInTheDocument();

			// Should show VIBE trial breakdown
			expect(screen.getByText("8 used / 15 total")).toBeInTheDocument();
			expect(screen.getByText("12 days")).toBeInTheDocument();
		});

		it("should NOT show welcome bonus banner when trial is expired", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.expiredTrial.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			// Should not show welcome bonus banner for expired trial
			expect(screen.queryByText("Bonus Credits")).not.toBeInTheDocument();
		});

		it("should filter out usage breakdown with zero usage limit and show only available items", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.userWithFilteredTrialItems.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			// Should show VIBE in regular usage breakdown (not in welcome bonus - has no freeTrialUsage)
			expect(screen.getByText("Vibe")).toBeInTheDocument();
			expect(
				screen.getByText("450 used / 1,500 covered in plan"),
			).toBeInTheDocument();

			// Should NOT show SPEC in the estimated usage section (filtered out - has freeTrialUsage AND usageLimit 0)
			const estimatedUsageSection = screen
				.getByText("Estimated Usage")
				.closest("div");
			expect(estimatedUsageSection).toBeInTheDocument();
			expect(
				within(estimatedUsageSection!).queryByText("Spec"),
			).not.toBeInTheDocument();
		});

		it("should show disabled state text for items with no trial and zero usage limit", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.freeUserNoTrial.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			// Should show SPEC as disabled with upgrade text
			expect(screen.getByText("Spec")).toBeInTheDocument();
			expect(
				screen.getByText("Upgrade plan to get spec requests"),
			).toBeInTheDocument();

			// Should show VIBE normally (has usage limit > 0)
			expect(screen.getByText("Vibe")).toBeInTheDocument();
			expect(
				screen.getByText("2 used / 10 covered in plan"),
			).toBeInTheDocument();

			// Should not show welcome bonus (no trial)
			expect(screen.queryByText("Bonus Credits")).not.toBeInTheDocument();
		});

		it("should show welcome bonus banner for SPEC but not VIBE when SPEC has fully used trial with days remaining and VIBE has pending usage with days over", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.fullyUsedTrialUser.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			// Should show welcome bonus banner
			expect(screen.getByText("Bonus Credits")).toBeInTheDocument();

			// Should show SPEC in the banner (fully used but has days remaining)
			expect(screen.getByText("Spec")).toBeInTheDocument();
			expect(screen.getByText("500 used / 500 total")).toBeInTheDocument();
			expect(screen.getByText("5 days")).toBeInTheDocument();

			// Should NOT show VIBE in the banner (has pending usage but days are over)
			const vibeElements = screen.queryAllByText("Vibe");
			// VIBE should only appear in the regular usage section, not in the banner
			expect(vibeElements.length).toBe(1);

			// Should show normal usage for VIBE in the usage section
			expect(
				screen.getByText("8 used / 10 covered in plan"),
			).toBeInTheDocument();
		});
	});

	describe("Paid User Scenarios", () => {
		it("should show manage plan button for power users", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.powerUserBillingTest.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			expect(screen.getByText("Manage Plan")).toBeInTheDocument();
			expect(screen.queryByText("Upgrade Plan")).not.toBeInTheDocument();
		});

		it("should show overage settings for paid users", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.paidUserWithOverages.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			// Paid users should see overage settings
			expect(screen.getByText("Overages")).toBeInTheDocument();
		});

		it("should show overage charges for users with overages", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.paidUserWithOverages.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			// Check for overage information (formatted with commas)
			// Note: The component shows Math.min(currentUsage, usageLimit) for display
			expect(
				screen.getByText("4,800 used / 5,000 covered in plan"),
			).toBeInTheDocument();
			expect(
				screen.getByText("50 used / 50 covered in plan"),
			).toBeInTheDocument();
		});
	});

	describe("Internal User Scenarios", () => {
		it("should show only user info for internal sign-in provider users", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.internalSignInUser.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			// Should show user info but not usage details
			expect(screen.getByText("internal@company.com")).toBeInTheDocument();
			expect(screen.queryByText("Spec")).not.toBeInTheDocument();
			expect(screen.queryByText("Vibe")).not.toBeInTheDocument();
		});
	});

	describe("Subscription Type Edge Cases", () => {
		it("should show subscription not available message for standalone subscriptions", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: {
					...mockUsageLimitsData.freeUserLowUsage.data!,
					subscriptionInfo: {
						...mockUsageLimitsData.freeUserLowUsage.data!.subscriptionInfo,
						subscriptionType: "Q_DEVELOPER_STANDALONE" as any,
					},
				},
				loading: false,
				error: null,
			});

			renderWithContext();

			expect(
				screen.getByText("Subscription Plan Not Available"),
			).toBeInTheDocument();
			expect(
				screen.getByText(
					"Your current subscription plan is no longer available. Please contact support for assistance with your account.",
				),
			).toBeInTheDocument();
		});

		it("should show manage plan button for non-upgrade capable users with MANAGE target", () => {
			mockUseUsageLimits.mockReturnValue({
				usageLimits: mockUsageLimitsData.userNotUpgradeCapable.data!,
				loading: false,
				error: null,
			});

			renderWithContext();

			expect(screen.getByText("Manage Plan")).toBeInTheDocument();
			expect(screen.queryByText("Upgrade Plan")).not.toBeInTheDocument();
		});
	});

	describe("User ID Copy Functionality", () => {
		beforeEach(() => {
			// Mock clipboard API and execCommand
			Object.defineProperty(navigator, "clipboard", {
				value: {
					writeText: vi.fn().mockResolvedValue(undefined),
				},
				writable: true,
			});

			// Mock execCommand for fallback
			document.execCommand = vi.fn().mockReturnValue(true);
		});

		it("should display User ID when userInfo has userId", () => {
			const testData = {
				...mockUsageLimitsData.freeUserLowUsage.data!,
				userInfo: {
					...mockUsageLimitsData.freeUserLowUsage.data!.userInfo,
					userId: "test-user-id-123",
					email: "test@example.com",
					provider: {
						id: "Google" as ProviderId,
						label: "Google",
					},
					isLoggedIn: true,
				},
			};

			mockUseUsageLimits.mockReturnValue({
				usageLimits: testData,
				loading: false,
				error: null,
			});

			renderWithContext();

			expect(screen.getByText("User ID")).toBeInTheDocument();
			expect(screen.getByTestId("user-id")).toBeInTheDocument();
		});

		it("should not display User ID when userInfo has no userId", () => {
			const testData = {
				...mockUsageLimitsData.freeUserLowUsage.data!,
				userInfo: {
					...mockUsageLimitsData.freeUserLowUsage.data!.userInfo,
					userId: undefined,
					email: "test@example.com",
					provider: {
						id: "Google" as ProviderId,
						label: "Google",
					},
					isLoggedIn: true,
				},
			};

			mockUseUsageLimits.mockReturnValue({
				usageLimits: testData,
				loading: false,
				error: null,
			});

			renderWithContext();

			expect(screen.queryByTestId("user-id")).not.toBeInTheDocument();
		});

		it("should show divider between provider and User ID when both exist", () => {
			const testData = {
				...mockUsageLimitsData.freeUserLowUsage.data!,
				userInfo: {
					...mockUsageLimitsData.freeUserLowUsage.data!.userInfo,
					userId: "test-user-id-123",
					email: "test@example.com",
					provider: {
						id: "Google" as ProviderId,
						label: "Google",
					},
					isLoggedIn: true,
				},
			};

			mockUseUsageLimits.mockReturnValue({
				usageLimits: testData,
				loading: false,
				error: null,
			});

			renderWithContext();

			expect(screen.getByText("Signed in with Google")).toBeInTheDocument();
			expect(screen.getByText("|")).toBeInTheDocument();
			expect(screen.getByText("User ID")).toBeInTheDocument();
		});

		it("should not show divider when provider exists but no userId", () => {
			const testData = {
				...mockUsageLimitsData.freeUserLowUsage.data!,
				userInfo: {
					...mockUsageLimitsData.freeUserLowUsage.data!.userInfo,
					userId: undefined,
					email: "test@example.com",
					provider: {
						id: "Google" as ProviderId,
						label: "Google",
					},
					isLoggedIn: true,
				},
			};

			mockUseUsageLimits.mockReturnValue({
				usageLimits: testData,
				loading: false,
				error: null,
			});

			renderWithContext();

			expect(screen.getByText("Signed in with Google")).toBeInTheDocument();
			expect(screen.queryByText("|")).not.toBeInTheDocument();
		});

		it("should show copy button when User ID is displayed", () => {
			const testData = {
				...mockUsageLimitsData.freeUserLowUsage.data!,
				userInfo: {
					...mockUsageLimitsData.freeUserLowUsage.data!.userInfo,
					userId: "test-user-id-123",
					email: "test@example.com",
					isLoggedIn: true,
				},
			};

			mockUseUsageLimits.mockReturnValue({
				usageLimits: testData,
				loading: false,
				error: null,
			});

			renderWithContext();

			expect(screen.getByTestId("copy-user-id-button")).toBeInTheDocument();
		});

		it("should show tooltip with full userId on hover", async () => {
			const testUserId = "test-user-id-123-very-long-id";
			const testData = {
				...mockUsageLimitsData.freeUserLowUsage.data!,
				userInfo: {
					...mockUsageLimitsData.freeUserLowUsage.data!.userInfo,
					userId: testUserId,
					email: "test@example.com",
					isLoggedIn: true,
				},
			};

			mockUseUsageLimits.mockReturnValue({
				usageLimits: testData,
				loading: false,
				error: null,
			});

			renderWithContext();

			const userIdElement = screen.getByTestId("user-id");
			fireEvent.mouseEnter(userIdElement);

			await waitFor(() => {
				expect(screen.getByText(testUserId)).toBeInTheDocument();
			});
		});

		it("should copy userId to clipboard when copy button is clicked", async () => {
			const testUserId = "test-user-id-123";
			const testData = {
				...mockUsageLimitsData.freeUserLowUsage.data!,
				userInfo: {
					...mockUsageLimitsData.freeUserLowUsage.data!.userInfo,
					userId: testUserId,
					email: "test@example.com",
					isLoggedIn: true,
				},
			};

			mockUseUsageLimits.mockReturnValue({
				usageLimits: testData,
				loading: false,
				error: null,
			});

			renderWithContext();

			const copyButton = screen.getByTestId("copy-user-id-button");
			fireEvent.click(copyButton);

			// Wait for the copy action to complete
			await waitFor(() => {
				// Check if either clipboard.writeText was called OR execCommand was called as fallback
				const clipboardMock = navigator.clipboard.writeText as any;
				const execCommandMock = document.execCommand as any;
				expect(
					clipboardMock.mock.calls.length > 0 ||
						execCommandMock.mock.calls.length > 0,
				).toBe(true);
			});
		});

		it("should show success message after copying", async () => {
			const testUserId = "test-user-id-123";
			const testData = {
				...mockUsageLimitsData.freeUserLowUsage.data!,
				userInfo: {
					...mockUsageLimitsData.freeUserLowUsage.data!.userInfo,
					userId: testUserId,
					email: "test@example.com",
					isLoggedIn: true,
				},
			};

			mockUseUsageLimits.mockReturnValue({
				usageLimits: testData,
				loading: false,
				error: null,
			});

			renderWithContext();

			const copyButton = screen.getByTestId("copy-user-id-button");
			fireEvent.click(copyButton);

			await waitFor(() => {
				expect(screen.getByText("User ID copied")).toBeInTheDocument();
				expect(screen.getByText("✓")).toBeInTheDocument();
			});
		});

		it("should hide copy button when showing success message", async () => {
			const testUserId = "test-user-id-123";
			const testData = {
				...mockUsageLimitsData.freeUserLowUsage.data!,
				userInfo: {
					...mockUsageLimitsData.freeUserLowUsage.data!.userInfo,
					userId: testUserId,
					email: "test@example.com",
					isLoggedIn: true,
				},
			};

			mockUseUsageLimits.mockReturnValue({
				usageLimits: testData,
				loading: false,
				error: null,
			});

			renderWithContext();

			const copyButton = screen.getByTestId("copy-user-id-button");
			fireEvent.click(copyButton);

			await waitFor(() => {
				expect(screen.getByText("User ID copied")).toBeInTheDocument();
				expect(
					screen.queryByTestId("copy-user-id-button"),
				).not.toBeInTheDocument();
			});
		});

		it("should handle copy when modal elements are not found", async () => {
			Object.defineProperty(navigator, "clipboard", {
				value: undefined,
				writable: true,
			});

			const originalQuerySelector = document.querySelector;
			const mockQuerySelector = vi.fn().mockReturnValue(null);
			document.querySelector = mockQuerySelector;

			document.execCommand = vi.fn().mockReturnValue(true);

			const testData = {
				...mockUsageLimitsData.freeUserLowUsage.data!,
				userInfo: {
					...mockUsageLimitsData.freeUserLowUsage.data!.userInfo,
					userId: "test-user-id-123",
					email: "test@example.com",
					isLoggedIn: true,
				},
			};

			mockUseUsageLimits.mockReturnValue({
				usageLimits: testData,
				loading: false,
				error: null,
			});

			renderWithContext();

			const copyButton = screen.getByTestId("copy-user-id-button");
			fireEvent.click(copyButton);

			// Verify that querySelector was called (this would fail with old simple document.body code)
			expect(mockQuerySelector).toHaveBeenCalledWith(
				"#account-dashboard-modal",
			);

			// Verify copy still works despite modal not being found
			await waitFor(() => {
				expect(screen.getByText("User ID copied")).toBeInTheDocument();
			});

			document.querySelector = originalQuerySelector;
		});
	});
});
