import { fireEvent, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import React from "react";
import { DateField, MIN_MAX_ERROR } from "./DateField";

describe("DateField", () => {
  it("renders correctly", () => {
    render(<DateField aria-label="date-input" data-testid="custom-test-id" />);
    expect(screen.getByTestId("custom-test-id")).toBeInTheDocument();
    expect(screen.getByTestId("custom-test-id")).toHaveAttribute(
      "type",
      "date",
    );
  });

  it("applies data-testid to input element", () => {
    render(<DateField aria-label="date-input" data-testid="custom-test-id" />);
    expect(screen.getByTestId("custom-test-id")).toBeInTheDocument();
  });

  it("applies custom className", () => {
    render(
      <DateField
        className="custom-class"
        aria-label="date-input"
        data-testid="custom-test-id"
      />,
    );
    expect(screen.getByTestId("custom-test-id")).toHaveClass(
      "mobius-date-field",
    );
    expect(screen.getByTestId("custom-test-id")).toHaveClass("custom-class");
  });

  it("forwards props to TextField", () => {
    render(
      <DateField
        aria-label="date-input"
        placeholder="Select date"
        isDisabled
        data-testid="custom-test-id"
      />,
    );
    const input = screen.getByTestId("custom-test-id");
    expect(input).toHaveAttribute("placeholder", "Select date");
    expect(input).toBeDisabled();
  });

  it("applies min and max attributes", () => {
    render(
      <DateField
        aria-label="date-input"
        min="2023-01-01"
        max="2023-12-31"
        data-testid="custom-test-id"
      />,
    );
    const input = screen.getByTestId("custom-test-id");
    expect(input).toHaveAttribute("min", "2023-01-01");
    expect(input).toHaveAttribute("max", "2023-12-31");
  });

  it("formats defaultValue when format is provided", () => {
    render(
      <DateField
        aria-label="date-input"
        defaultValue="01/15/2023"
        format="mm/dd/yyyy"
        data-testid="custom-test-id"
      />,
    );
    const input = screen.getByTestId("custom-test-id");
    expect(input).toHaveValue("2023-01-15");
  });

  it("shows error for invalid min date", () => {
    render(
      <DateField
        aria-label="date-input"
        min="invalid-date"
        data-testid="custom-test-id"
      />,
    );
    expect(screen.getByText(/Invalid min date/)).toBeInTheDocument();
  });

  it("shows error for invalid max date", () => {
    render(
      <DateField
        aria-label="date-input"
        max="invalid-date"
        data-testid="custom-test-id"
      />,
    );
    expect(screen.getByText(/Invalid max date/)).toBeInTheDocument();
  });

  it("shows error when min is greater than max", () => {
    render(
      <DateField
        aria-label="date-input"
        min="2023-12-31"
        max="2023-01-01"
        data-testid="custom-test-id"
      />,
    );
    expect(screen.getByText(MIN_MAX_ERROR)).toBeInTheDocument();
  });

  it("accepts valid min and max values", () => {
    render(
      <DateField
        aria-label="date-input"
        min="2023-01-01"
        max="2023-12-31"
        data-testid="custom-test-id"
      />,
    );
    // Should not show error messages
    expect(screen.queryByText(/Invalid/)).not.toBeInTheDocument();
    expect(screen.queryByText(MIN_MAX_ERROR)).not.toBeInTheDocument();
  });

  it("passes ref to the underlying input", () => {
    const ref = React.createRef<HTMLInputElement>();
    render(
      <DateField
        aria-label="date-input"
        ref={ref}
        data-testid="custom-test-id"
      />,
    );
    expect(ref.current).not.toBeNull();
    expect(ref.current?.tagName).toBe("INPUT");
  });

  it("uses custom errorMessage when provided", () => {
    render(
      <DateField
        aria-label="date-input"
        errorMessage="Custom error message"
        data-testid="custom-test-id"
      />,
    );
    expect(screen.getByText("Custom error message")).toBeInTheDocument();
  });

  describe("DateField validation on blur", () => {
    it("calls onBlur handler with correct event on blur", async () => {
      const handleChange = vi.fn();

      render(
        <DateField
          aria-label="date-input"
          data-testid="date-field"
          onBlur={handleChange}
        />,
      );

      const input = screen.getByTestId("date-field");
      await userEvent.type(input, "2023-10-15");
      fireEvent.blur(input);

      expect(handleChange).toHaveBeenCalledTimes(1);

      expect(handleChange.mock.calls[0][0].target.value).toEqual("2023-10-15");
      expect(screen.queryByText("Invalid date input")).not.toBeInTheDocument();
    });

    it("validates against min date on blur", async () => {
      render(
        <DateField
          aria-label="date-input"
          data-testid="date-field"
          min="2023-10-10"
        />,
      );

      const input = screen.getByTestId("date-field");
      await userEvent.clear(input);
      await userEvent.type(input, "2023-10-05");
      fireEvent.blur(input);

      expect(screen.getByText("Invalid date input")).toBeInTheDocument();

      // Test valid date
      await userEvent.clear(input);
      await userEvent.type(input, "2023-10-15");
      fireEvent.blur(input);

      expect(screen.queryByText("Invalid date input")).not.toBeInTheDocument();
    });

    it("validates against max date on blur", async () => {
      render(
        <DateField
          aria-label="date-input"
          data-testid="date-field"
          max="2023-10-20"
        />,
      );

      const input = screen.getByTestId("date-field");
      await userEvent.clear(input);
      await userEvent.type(input, "2023-10-25");
      fireEvent.blur(input);

      expect(screen.getByText("Invalid date input")).toBeInTheDocument();
    });

    it("resets validation state when valid input is provided after invalid input", async () => {
      render(
        <DateField
          aria-label="date-input"
          data-testid="date-field"
          min="2023-01-01"
          max="2023-12-31"
        />,
      );

      const input = screen.getByTestId("date-field");

      // Enter invalid date
      await userEvent.clear(input);
      await userEvent.type(input, "2024-01-15");
      fireEvent.blur(input);

      expect(screen.getByText("Invalid date input")).toBeInTheDocument();

      // Enter valid date
      await userEvent.clear(input);
      await userEvent.type(input, "2023-06-15");
      fireEvent.blur(input);

      expect(screen.queryByText("Invalid date input")).not.toBeInTheDocument();
    });
  });
});
