import React from "react";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { LoginForm } from "@/components/auth/login-form";
import { useAuth, useEmailValidation } from "@/hooks/use-auth";

// Mock the hooks
jest.mock("@/hooks/use-auth");
jest.mock("@/service/landing/landing", () => ({
  listRole: jest.fn().mockResolvedValue({
    data: {
      data: [
        { id: 1, name: "Admin" },
        { id: 2, name: "User" },
      ],
    },
  }),
}));

// Mock next-intl
jest.mock("next-intl", () => ({
  useTranslations: () => (key: string, options?: any) => {
    const defaults = {
      logInPlease: "Log In Please",
      acc: "Acc",
      register: "Register",
      password: "Password",
      rememberMe: "Remember Me",
      forgotPass: "Forgot Pass",
      next: "Next",
      categoryReg: "Category Reg",
      selectOne: "Select One",
      signIn: "Sign In",
    };
    return options?.defaultValue || defaults[key] || key;
  },
}));

const mockUseAuth = useAuth as jest.MockedFunction<typeof useAuth>;
const mockUseEmailValidation = useEmailValidation as jest.MockedFunction<typeof useEmailValidation>;

describe("LoginForm", () => {
  const mockLogin = jest.fn();
  const mockValidateEmail = jest.fn();
  const mockOnSuccess = jest.fn();
  const mockOnError = jest.fn();

  beforeEach(() => {
    jest.clearAllMocks();
    
    mockUseAuth.mockReturnValue({
      login: mockLogin,
      logout: jest.fn(),
      refreshToken: jest.fn(),
      isAuthenticated: false,
      user: null,
      loading: false,
      error: null,
    });

    mockUseEmailValidation.mockReturnValue({
      validateEmail: mockValidateEmail,
      loading: false,
      error: null,
    });
  });

  it("renders login form with all required fields", () => {
    render(
      <LoginForm
        onSuccess={mockOnSuccess}
        onError={mockOnError}
      />
    );

    expect(screen.getByText("Log In Please")).toBeInTheDocument();
    expect(screen.getByLabelText(/username/i)).toBeInTheDocument();
    expect(screen.getByLabelText(/password/i)).toBeInTheDocument();
    expect(screen.getByRole("button", { name: /selanjutnya/i })).toBeInTheDocument();
  });

  it("shows validation errors for invalid input", async () => {
    render(
      <LoginForm
        onSuccess={mockOnSuccess}
        onError={mockOnError}
      />
    );

    const submitButton = screen.getByRole("button", { name: /selanjutnya/i });
    fireEvent.click(submitButton);

    await waitFor(() => {
      expect(screen.getByText("Username is required")).toBeInTheDocument();
      expect(screen.getByText("Password is required")).toBeInTheDocument();
    });
  });

  it("handles successful form submission", async () => {
    mockValidateEmail.mockResolvedValue("success");

    render(
      <LoginForm
        onSuccess={mockOnSuccess}
        onError={mockOnError}
      />
    );

    const usernameInput = screen.getByLabelText(/username/i);
    const passwordInput = screen.getByLabelText(/password/i);
    const submitButton = screen.getByRole("button", { name: /selanjutnya/i });

    fireEvent.change(usernameInput, { target: { value: "testuser" } });
    fireEvent.change(passwordInput, { target: { value: "password123" } });
    fireEvent.click(submitButton);

    await waitFor(() => {
      expect(mockValidateEmail).toHaveBeenCalledWith({
        username: "testuser",
        password: "password123",
      });
    });
  });

  it("handles email validation step", async () => {
    mockValidateEmail.mockResolvedValue("setup");

    render(
      <LoginForm
        onSuccess={mockOnSuccess}
        onError={mockOnError}
      />
    );

    const usernameInput = screen.getByLabelText(/username/i);
    const passwordInput = screen.getByLabelText(/password/i);
    const submitButton = screen.getByRole("button", { name: /selanjutnya/i });

    fireEvent.change(usernameInput, { target: { value: "testuser" } });
    fireEvent.change(passwordInput, { target: { value: "password123" } });
    fireEvent.click(submitButton);

    await waitFor(() => {
      expect(mockOnError).toHaveBeenCalledWith("Email setup required");
    });
  });

  it("handles OTP step", async () => {
    mockValidateEmail.mockResolvedValue("otp");

    render(
      <LoginForm
        onSuccess={mockOnSuccess}
        onError={mockOnError}
      />
    );

    const usernameInput = screen.getByLabelText(/username/i);
    const passwordInput = screen.getByLabelText(/password/i);
    const submitButton = screen.getByRole("button", { name: /selanjutnya/i });

    fireEvent.change(usernameInput, { target: { value: "testuser" } });
    fireEvent.change(passwordInput, { target: { value: "password123" } });
    fireEvent.click(submitButton);

    await waitFor(() => {
      expect(mockOnError).toHaveBeenCalledWith("OTP verification required");
    });
  });

  it("toggles password visibility", () => {
    render(
      <LoginForm
        onSuccess={mockOnSuccess}
        onError={mockOnError}
      />
    );

    const passwordInput = screen.getByLabelText(/password/i);
    const toggleButton = screen.getByLabelText(/show password/i);

    expect(passwordInput).toHaveAttribute("type", "password");
    
    fireEvent.click(toggleButton);
    expect(passwordInput).toHaveAttribute("type", "text");
    expect(screen.getByLabelText(/hide password/i)).toBeInTheDocument();
    
    fireEvent.click(toggleButton);
    expect(passwordInput).toHaveAttribute("type", "password");
  });

  it("handles remember me checkbox", () => {
    render(
      <LoginForm
        onSuccess={mockOnSuccess}
        onError={mockOnError}
      />
    );

    const rememberMeCheckbox = screen.getByRole("checkbox", { name: /remember me/i });
    
    expect(rememberMeCheckbox).toBeChecked();
    
    fireEvent.click(rememberMeCheckbox);
    expect(rememberMeCheckbox).not.toBeChecked();
  });

  it("opens registration dialog", () => {
    render(
      <LoginForm
        onSuccess={mockOnSuccess}
        onError={mockOnError}
      />
    );

    const registerLink = screen.getByText("Register");
    fireEvent.click(registerLink);

    expect(screen.getByText("Category Reg")).toBeInTheDocument();
    expect(screen.getByText("Select One")).toBeInTheDocument();
    expect(screen.getByLabelText("Admin")).toBeInTheDocument();
    expect(screen.getByLabelText("User")).toBeInTheDocument();
  });

  it("handles loading state", async () => {
    mockUseEmailValidation.mockReturnValue({
      validateEmail: mockValidateEmail,
      loading: true,
      error: null,
    });

    render(
      <LoginForm
        onSuccess={mockOnSuccess}
        onError={mockOnError}
      />
    );

    const submitButton = screen.getByRole("button", { name: /processing/i });
    expect(submitButton).toBeDisabled();
  });

  it("handles error state", async () => {
    mockValidateEmail.mockRejectedValue(new Error("Validation failed"));

    render(
      <LoginForm
        onSuccess={mockOnSuccess}
        onError={mockOnError}
      />
    );

    const usernameInput = screen.getByLabelText(/username/i);
    const passwordInput = screen.getByLabelText(/password/i);
    const submitButton = screen.getByRole("button", { name: /selanjutnya/i });

    fireEvent.change(usernameInput, { target: { value: "testuser" } });
    fireEvent.change(passwordInput, { target: { value: "password123" } });
    fireEvent.click(submitButton);

    await waitFor(() => {
      expect(mockOnError).toHaveBeenCalledWith("Validation failed");
    });
  });
}); 