import { SegmentFilter } from "@/modules/ee/contacts/segments/components/segment-filter";
import * as segmentUtils from "@/modules/ee/contacts/segments/lib/utils";
import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
import { TContactAttributeKey } from "@formbricks/types/contact-attribute-key";
import {
  TSegment,
  TSegmentAttributeFilter,
  TSegmentDeviceFilter,
  TSegmentPersonFilter,
  TSegmentSegmentFilter,
} from "@formbricks/types/segment";

// Mock ResizeObserver
const ResizeObserverMock = vi.fn(() => ({
  observe: vi.fn(),
  unobserve: vi.fn(),
  disconnect: vi.fn(),
}));

vi.stubGlobal("ResizeObserver", ResizeObserverMock);

// Mock dependencies
vi.mock("@/lib/utils/strings", () => ({
  isCapitalized: vi.fn((str) => str === "Email"),
}));

vi.mock("@/modules/ee/contacts/segments/lib/utils", () => ({
  convertOperatorToText: vi.fn((op) => op),
  convertOperatorToTitle: vi.fn((op) => op),
  toggleFilterConnector: vi.fn(),
  updateContactAttributeKeyInFilter: vi.fn(),
  updateDeviceTypeInFilter: vi.fn(),
  updateFilterValue: vi.fn(),
  updateOperatorInFilter: vi.fn(),
  updatePersonIdentifierInFilter: vi.fn(),
  updateSegmentIdInFilter: vi.fn(),
  getOperatorOptions: vi.fn(() => []),
  validateFilterValue: vi.fn(() => ({ isValid: true, message: "" })),
}));

vi.mock("@/modules/ui/components/button", () => ({
  Button: ({ children, onClick, disabled, ...props }: any) => (
    <button onClick={onClick} disabled={disabled} {...props}>
      {children}
    </button>
  ),
}));

vi.mock("@/modules/ui/components/dropdown-menu", () => ({
  DropdownMenu: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
  DropdownMenuTrigger: ({ children, disabled }: { children: React.ReactNode; disabled?: boolean }) => (
    <button data-testid="dropdown-trigger" disabled={disabled}>
      {children}
    </button>
  ),
  DropdownMenuContent: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="dropdown-content">{children}</div>
  ),
  DropdownMenuItem: ({ children, onClick, icon }: any) => (
    <button onClick={onClick}>
      {icon}
      {children}
    </button>
  ),
}));

// Remove the mock for Input component

vi.mock("./add-filter-modal", () => ({
  AddFilterModal: ({ open, setOpen, onAddFilter }: any) =>
    open ? (
      <div data-testid="add-filter-modal">
        <span>Add Filter Modal</span>
        <button onClick={() => onAddFilter({})}>Add</button>
        <hr />
        <button onClick={() => setOpen(false)}>Close</button>
      </div>
    ) : null,
}));

vi.mock("lucide-react", () => ({
  ArrowDownIcon: () => <div data-testid="arrow-down-icon">ArrowDown</div>,
  ArrowUpIcon: () => <div data-testid="arrow-up-icon">ArrowUp</div>,
  FingerprintIcon: () => <div data-testid="fingerprint-icon">Fingerprint</div>,
  MonitorSmartphoneIcon: () => <div data-testid="monitor-icon">Monitor</div>,
  MoreVertical: () => <div data-testid="more-vertical-icon">MoreVertical</div>,
  TagIcon: () => <div data-testid="tag-icon">Tag</div>,
  Trash2: () => <div data-testid="trash-icon">Trash</div>,
  Users2Icon: () => <div data-testid="users-icon">Users</div>,
}));

vi.mock("@tolgee/react", () => ({
  useTranslate: () => ({
    t: (key: string) => key,
  }),
}));

const mockSetSegment = vi.fn();
const mockHandleAddFilterBelow = vi.fn();
const mockOnCreateGroup = vi.fn();
const mockOnDeleteFilter = vi.fn();
const mockOnMoveFilter = vi.fn();

const environmentId = "test-env-id";
const segment = {
  id: "seg1",
  environmentId,
  title: "Test Segment",
  isPrivate: false,
  filters: [],
  surveys: ["survey1"],
  createdAt: new Date(),
  updatedAt: new Date(),
} as unknown as TSegment;
const segments: TSegment[] = [
  segment,
  {
    id: "seg2",
    environmentId,
    title: "Another Segment",
    isPrivate: false,
    filters: [],
    surveys: ["survey1"],
    createdAt: new Date(),
    updatedAt: new Date(),
  } as unknown as TSegment,
  {
    id: "seg3",
    environmentId,
    title: "Third Segment",
    isPrivate: false,
    filters: [],
    surveys: ["survey1"],
    createdAt: new Date(),
    updatedAt: new Date(),
  } as unknown as TSegment,
];
const contactAttributeKeys: TContactAttributeKey[] = [
  {
    id: "attr1",
    key: "email",
    name: "Email",
    environmentId,
    createdAt: new Date(),
    updatedAt: new Date(),
  } as TContactAttributeKey,
  {
    id: "attr2",
    key: "userId",
    name: "User ID",
    environmentId,
    createdAt: new Date(),
    updatedAt: new Date(),
  } as TContactAttributeKey,
  {
    id: "attr3",
    key: "plan",
    name: "Plan",
    environmentId,
    createdAt: new Date(),
    updatedAt: new Date(),
  } as TContactAttributeKey,
];

const baseProps = {
  environmentId,
  segment,
  segments,
  contactAttributeKeys,
  setSegment: mockSetSegment,
  handleAddFilterBelow: mockHandleAddFilterBelow,
  onCreateGroup: mockOnCreateGroup,
  onDeleteFilter: mockOnDeleteFilter,
  onMoveFilter: mockOnMoveFilter,
};

describe("SegmentFilter", () => {
  afterEach(() => {
    cleanup();
    vi.clearAllMocks();
  });

  beforeEach(() => {
    // Remove the implementation that modifies baseProps.segment during the test.
    // vi.clearAllMocks() in afterEach handles mock reset.
  });

  test("SegmentFilterItemConnector displays correct connector value or default text", async () => {
    const attributeFilterResource: TSegmentAttributeFilter = {
      id: "filter-attr-1",
      root: {
        type: "attribute",
        contactAttributeKey: "email",
      },
      qualifier: {
        operator: "equals",
      },
      value: "test@example.com",
    };
    const segmentWithAttributeFilter: TSegment = {
      ...segment,
      filters: [
        {
          id: "group-1",
          connector: "and",
          resource: attributeFilterResource,
        },
      ],
    };

    const currentProps = { ...baseProps, segment: segmentWithAttributeFilter };

    render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);
    expect(screen.getByText("and")).toBeInTheDocument();

    cleanup();
    render(<SegmentFilter {...currentProps} connector={null} resource={attributeFilterResource} />);
    expect(screen.getByText("environments.segments.where")).toBeInTheDocument();
  });

  test("SegmentFilterItemConnector applies correct CSS classes based on props", async () => {
    const attributeFilterResource: TSegmentAttributeFilter = {
      id: "filter-attr-1",
      root: {
        type: "attribute",
        contactAttributeKey: "email",
      },
      qualifier: {
        operator: "equals",
      },
      value: "test@example.com",
    };
    const segmentWithAttributeFilter: TSegment = {
      ...segment,
      filters: [
        {
          id: "group-1",
          connector: "and",
          resource: attributeFilterResource,
        },
      ],
    };

    const currentProps = { ...baseProps, segment: segmentWithAttributeFilter };

    // Test case 1: connector is "and", viewOnly is false
    render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);
    const connectorButton1 = screen.getByText("and").closest("button");
    expect(connectorButton1).toHaveClass("cursor-pointer");
    expect(connectorButton1).toHaveClass("underline");
    expect(connectorButton1).not.toHaveClass("cursor-not-allowed");

    cleanup();

    // Test case 2: connector is null, viewOnly is false
    render(<SegmentFilter {...currentProps} connector={null} resource={attributeFilterResource} />);
    const connectorButton2 = screen.getByText("environments.segments.where").closest("button");
    expect(connectorButton2).not.toHaveClass("cursor-pointer");
    expect(connectorButton2).not.toHaveClass("underline");
    expect(connectorButton2).not.toHaveClass("cursor-not-allowed");

    cleanup();

    // Test case 3: connector is "and", viewOnly is true
    render(
      <SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} viewOnly={true} />
    );
    const connectorButton3 = screen.getByText("and").closest("button");
    expect(connectorButton3).not.toHaveClass("cursor-pointer");
    expect(connectorButton3).toHaveClass("underline");
    expect(connectorButton3).toHaveClass("cursor-not-allowed");
  });

  test("SegmentFilterItemConnector applies cursor-not-allowed class when viewOnly is true", async () => {
    const attributeFilterResource: TSegmentAttributeFilter = {
      id: "filter-attr-1",
      root: {
        type: "attribute",
        contactAttributeKey: "email",
      },
      qualifier: {
        operator: "equals",
      },
      value: "test@example.com",
    };
    const segmentWithAttributeFilter: TSegment = {
      ...segment,
      filters: [
        {
          id: "group-1",
          connector: "and",
          resource: attributeFilterResource,
        },
      ],
    };

    const currentProps = { ...baseProps, segment: segmentWithAttributeFilter, viewOnly: true };

    render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);
    const connectorButton = screen.getByText("and");
    expect(connectorButton).toHaveClass("cursor-not-allowed");
  });

  test("toggles connector on Enter key press", async () => {
    const attributeFilterResource: TSegmentAttributeFilter = {
      id: "filter-attr-1",
      root: { type: "attribute", contactAttributeKey: "email" },
      qualifier: { operator: "equals" },
      value: "test@example.com",
    };
    const segmentWithAttributeFilter: TSegment = {
      ...segment,
      filters: [
        {
          id: "group-1",
          connector: "and",
          resource: attributeFilterResource,
        },
      ],
    };

    const currentProps = { ...baseProps, segment: structuredClone(segmentWithAttributeFilter) };

    render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);
    const connectorButton = screen.getByText("and");
    connectorButton.focus();
    await userEvent.keyboard("{Enter}");

    expect(vi.mocked(segmentUtils.toggleFilterConnector)).toHaveBeenCalledWith(
      currentProps.segment.filters,
      attributeFilterResource.id,
      "or"
    );
    expect(mockSetSegment).toHaveBeenCalled();
  });

  test("SegmentFilterItemConnector button shows a visible focus indicator when focused via keyboard navigation", async () => {
    const attributeFilterResource: TSegmentAttributeFilter = {
      id: "filter-attr-1",
      root: {
        type: "attribute",
        contactAttributeKey: "email",
      },
      qualifier: {
        operator: "equals",
      },
      value: "test@example.com",
    };
    const segmentWithAttributeFilter: TSegment = {
      ...segment,
      filters: [
        {
          id: "group-1",
          connector: "and",
          resource: attributeFilterResource,
        },
      ],
    };

    const currentProps = { ...baseProps, segment: segmentWithAttributeFilter };
    render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);

    const connectorButton = screen.getByText("and");
    await userEvent.tab();
    expect(connectorButton).toHaveFocus();
  });

  test("SegmentFilterItemConnector button has aria-label for screen readers", async () => {
    const attributeFilterResource: TSegmentAttributeFilter = {
      id: "filter-attr-1",
      root: {
        type: "attribute",
        contactAttributeKey: "email",
      },
      qualifier: {
        operator: "equals",
      },
      value: "test@example.com",
    };
    const segmentWithAttributeFilter: TSegment = {
      ...segment,
      filters: [
        {
          id: "group-1",
          connector: "and",
          resource: attributeFilterResource,
        },
      ],
    };

    const currentProps = { ...baseProps, segment: segmentWithAttributeFilter };

    render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);
    const andButton = screen.getByRole("button", { name: "and" });
    expect(andButton).toHaveAttribute("aria-label", "and");

    cleanup();
    render(<SegmentFilter {...currentProps} connector="or" resource={attributeFilterResource} />);
    const orButton = screen.getByRole("button", { name: "or" });
    expect(orButton).toHaveAttribute("aria-label", "or");

    cleanup();
    render(<SegmentFilter {...currentProps} connector={null} resource={attributeFilterResource} />);
    const whereButton = screen.getByRole("button", { name: "environments.segments.where" });
    expect(whereButton).toHaveAttribute("aria-label", "environments.segments.where");
  });

  describe("Attribute Filter", () => {
    const attributeFilterResource: TSegmentAttributeFilter = {
      id: "filter-attr-1",
      root: {
        type: "attribute",
        contactAttributeKey: "email",
      },
      qualifier: {
        operator: "equals",
      },
      value: "test@example.com",
    };
    const segmentWithAttributeFilter: TSegment = {
      ...segment,
      filters: [
        {
          id: "group-1",
          connector: "and",
          resource: attributeFilterResource,
        },
      ],
    };

    test("renders correctly", async () => {
      const currentProps = { ...baseProps, segment: segmentWithAttributeFilter };
      render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);
      expect(screen.getByText("and")).toBeInTheDocument();
      await waitFor(() => expect(screen.getByText("Email").closest("button")).toBeInTheDocument());
      await waitFor(() => expect(screen.getByText("equals").closest("button")).toBeInTheDocument());
      expect(screen.getByDisplayValue("test@example.com")).toBeInTheDocument();
      expect(screen.getByTestId("dropdown-trigger")).toBeInTheDocument();
      expect(screen.getByTestId("trash-icon")).toBeInTheDocument();
    });

    test("renders attribute key select correctly", async () => {
      const currentProps = { ...baseProps, segment: structuredClone(segmentWithAttributeFilter) };
      render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);

      await waitFor(() => expect(screen.getByText("Email").closest("button")).toBeInTheDocument());

      expect(vi.mocked(segmentUtils.updateContactAttributeKeyInFilter)).not.toHaveBeenCalled();
      expect(mockSetSegment).not.toHaveBeenCalled();
    });

    test("renders operator select correctly", async () => {
      const currentProps = { ...baseProps, segment: structuredClone(segmentWithAttributeFilter) };
      render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);

      await waitFor(() => expect(screen.getByText("equals").closest("button")).toBeInTheDocument());

      expect(vi.mocked(segmentUtils.updateOperatorInFilter)).not.toHaveBeenCalled();
      expect(mockSetSegment).not.toHaveBeenCalled();
    });

    test("handles value change", async () => {
      const initialSegment = structuredClone(segmentWithAttributeFilter);
      const currentProps = { ...baseProps, segment: initialSegment, setSegment: mockSetSegment };

      render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);
      const valueInput = screen.getByDisplayValue("test@example.com");

      // Clear the input
      await userEvent.clear(valueInput);
      // Fire a single change event with the final value
      fireEvent.change(valueInput, { target: { value: "new@example.com" } });

      // Check the call to the update function (might be called once or twice by checkValueAndUpdate)
      await waitFor(() => {
        // Check if it was called AT LEAST once with the correct final value
        expect(vi.mocked(segmentUtils.updateFilterValue)).toHaveBeenCalledWith(
          expect.anything(),
          attributeFilterResource.id,
          "new@example.com"
        );
      });

      // Ensure the state update function was called
      expect(mockSetSegment).toHaveBeenCalled();
    });

    test("renders viewOnly mode correctly", async () => {
      const currentProps = { ...baseProps, segment: segmentWithAttributeFilter };
      render(
        <SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} viewOnly={true} />
      );
      expect(screen.getByText("and")).toHaveClass("cursor-not-allowed");
      await waitFor(() => expect(screen.getByText("Email").closest("button")).toBeDisabled());
      await waitFor(() => expect(screen.getByText("equals").closest("button")).toBeDisabled());
      expect(screen.getByDisplayValue("test@example.com")).toBeDisabled();
      expect(screen.getByTestId("dropdown-trigger")).toBeDisabled();
      expect(screen.getByTestId("trash-icon").closest("button")).toBeDisabled();
    });

    test("displays error message for non-numeric input with arithmetic operator", async () => {
      const arithmeticFilterResource: TSegmentAttributeFilter = {
        id: "filter-attr-arithmetic-1",
        root: {
          type: "attribute",
          contactAttributeKey: "email",
        },
        qualifier: {
          operator: "greaterThan",
        },
        value: "hello",
      };

      const segmentWithArithmeticFilter: TSegment = {
        ...segment,
        filters: [
          {
            id: "group-1",
            connector: "and",
            resource: arithmeticFilterResource,
          },
        ],
      };

      const currentProps = { ...baseProps, segment: segmentWithArithmeticFilter };
      render(<SegmentFilter {...currentProps} connector="and" resource={arithmeticFilterResource} />);

      const valueInput = screen.getByDisplayValue("hello");
      await userEvent.clear(valueInput);
      fireEvent.change(valueInput, { target: { value: "abc" } });

      await waitFor(() =>
        expect(screen.getByText("environments.segments.value_must_be_a_number")).toBeInTheDocument()
      );
    });

    test("navigates with tab key", async () => {
      const attributeFilterResource: TSegmentAttributeFilter = {
        id: "filter-attr-1",
        root: {
          type: "attribute",
          contactAttributeKey: "email",
        },
        qualifier: {
          operator: "equals",
        },
        value: "test@example.com",
      };
      const segmentWithAttributeFilter: TSegment = {
        ...segment,
        filters: [
          {
            id: "group-1",
            connector: "and",
            resource: attributeFilterResource,
          },
        ],
      };

      const currentProps = { ...baseProps, segment: segmentWithAttributeFilter };
      render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);

      const connectorButton = screen.getByText("and").closest("button");
      const attributeSelect = screen.getByText("Email").closest("button");
      const operatorSelect = screen.getByText("equals").closest("button");
      const valueInput = screen.getByDisplayValue("test@example.com");
      const dropdownTrigger = screen.getByTestId("dropdown-trigger");
      const trashButton = screen.getByTestId("trash-icon").closest("button");

      // Set focus on the first element (connector button)
      connectorButton?.focus();
      await waitFor(() => expect(connectorButton).toHaveFocus());

      // Tab to attribute select
      await userEvent.tab();
      if (!attributeSelect) throw new Error("attributeSelect is null");
      await waitFor(() => expect(attributeSelect).toHaveFocus());

      // Tab to operator select
      await userEvent.tab();
      if (!operatorSelect) throw new Error("operatorSelect is null");
      await waitFor(() => expect(operatorSelect).toHaveFocus());

      // Tab to value input
      await userEvent.tab();
      await waitFor(() => expect(valueInput).toHaveFocus());

      // Tab to dropdown trigger
      await userEvent.tab();
      await waitFor(() => expect(dropdownTrigger).toHaveFocus());

      // Tab through dropdown menu items (4 items)
      for (let i = 0; i < 4; i++) {
        await userEvent.tab();
      }

      // Tab to trash button
      await userEvent.tab();
      if (!trashButton) throw new Error("trashButton is null");
      await waitFor(() => expect(trashButton).toHaveFocus());
    });

    test("interactive buttons have type='button' attribute", async () => {
      const attributeFilterResource: TSegmentAttributeFilter = {
        id: "filter-attr-1",
        root: {
          type: "attribute",
          contactAttributeKey: "email",
        },
        qualifier: {
          operator: "equals",
        },
        value: "test@example.com",
      };
      const segmentWithAttributeFilter: TSegment = {
        ...segment,
        filters: [
          {
            id: "group-1",
            connector: "and",
            resource: attributeFilterResource,
          },
        ],
      };

      const currentProps = { ...baseProps, segment: segmentWithAttributeFilter };
      render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);

      const connectorButton = await screen.findByText("and");
      expect(connectorButton.closest("button")).toHaveAttribute("type", "button");
    });
  });

  describe("Person Filter", () => {
    const personFilterResource: TSegmentPersonFilter = {
      id: "filter-person-1",
      root: { type: "person", personIdentifier: "userId" },
      qualifier: { operator: "equals" },
      value: "person123",
    };
    const segmentWithPersonFilter: TSegment = {
      ...segment,
      filters: [{ id: "group-1", connector: "and", resource: personFilterResource }],
    };

    test("renders correctly", async () => {
      const currentProps = { ...baseProps, segment: segmentWithPersonFilter };
      render(<SegmentFilter {...currentProps} connector="or" resource={personFilterResource} />);
      expect(screen.getByText("or")).toBeInTheDocument();
      await waitFor(() => expect(screen.getByText("userId").closest("button")).toBeInTheDocument());
      await waitFor(() => expect(screen.getByText("equals").closest("button")).toBeInTheDocument());
      expect(screen.getByDisplayValue("person123")).toBeInTheDocument();
    });

    test("renders operator select correctly", async () => {
      const currentProps = { ...baseProps, segment: structuredClone(segmentWithPersonFilter) };
      render(<SegmentFilter {...currentProps} connector="or" resource={personFilterResource} />);

      await waitFor(() => expect(screen.getByText("equals").closest("button")).toBeInTheDocument());

      expect(vi.mocked(segmentUtils.updateOperatorInFilter)).not.toHaveBeenCalled();
      expect(mockSetSegment).not.toHaveBeenCalled();
    });

    test("handles value change", async () => {
      const initialSegment = structuredClone(segmentWithPersonFilter);
      const currentProps = { ...baseProps, segment: initialSegment, setSegment: mockSetSegment };

      render(<SegmentFilter {...currentProps} connector="or" resource={personFilterResource} />);
      const valueInput = screen.getByDisplayValue("person123");

      // Clear the input
      await userEvent.clear(valueInput);
      // Fire a single change event with the final value
      fireEvent.change(valueInput, { target: { value: "person456" } });

      // Check the call to the update function (might be called once or twice by checkValueAndUpdate)
      await waitFor(() => {
        // Check if it was called AT LEAST once with the correct final value
        expect(vi.mocked(segmentUtils.updateFilterValue)).toHaveBeenCalledWith(
          expect.anything(),
          personFilterResource.id,
          "person456"
        );
      });
      // Ensure the state update function was called
      expect(mockSetSegment).toHaveBeenCalled();
    });

    test("displays error message for non-numeric input with arithmetic operator", async () => {
      const personFilterResourceWithArithmeticOperator: TSegmentPersonFilter = {
        id: "filter-person-2",
        root: { type: "person", personIdentifier: "userId" },
        qualifier: { operator: "greaterThan" },
        value: "hello",
      };

      const segmentWithPersonFilterArithmetic: TSegment = {
        ...segment,
        filters: [{ id: "group-2", connector: "and", resource: personFilterResourceWithArithmeticOperator }],
      };

      const currentProps = {
        ...baseProps,
        segment: structuredClone(segmentWithPersonFilterArithmetic),
        setSegment: mockSetSegment,
      };

      render(
        <SegmentFilter
          {...currentProps}
          connector="or"
          resource={personFilterResourceWithArithmeticOperator}
        />
      );
      const valueInput = screen.getByDisplayValue("hello");

      await userEvent.clear(valueInput);
      fireEvent.change(valueInput, { target: { value: "abc" } });

      await waitFor(() => {
        expect(screen.getByText("environments.segments.value_must_be_a_number")).toBeInTheDocument();
      });
    });

    test("handles empty value input", async () => {
      const initialSegment = structuredClone(segmentWithPersonFilter);
      const currentProps = { ...baseProps, segment: initialSegment, setSegment: mockSetSegment };

      render(<SegmentFilter {...currentProps} connector="or" resource={personFilterResource} />);
      const valueInput = screen.getByDisplayValue("person123");

      // Clear the input
      await userEvent.clear(valueInput);
      // Fire a single change event with the final value
      fireEvent.change(valueInput, { target: { value: "" } });

      // Check the call to the update function (might be called once or twice by checkValueAndUpdate)
      await waitFor(() => {
        // Check if it was called AT LEAST once with the correct final value
        expect(vi.mocked(segmentUtils.updateFilterValue)).toHaveBeenCalledWith(
          expect.anything(),
          personFilterResource.id,
          ""
        );
      });

      const errorMessage = await screen.findByText("environments.segments.value_cannot_be_empty");
      expect(errorMessage).toBeVisible();

      // Ensure the state update function was called
      expect(mockSetSegment).toHaveBeenCalled();
    });

    test("is keyboard accessible", async () => {
      const currentProps = { ...baseProps, segment: segmentWithPersonFilter };
      render(<SegmentFilter {...currentProps} connector="or" resource={personFilterResource} />);

      // Tab to the connector button
      await userEvent.tab();
      expect(screen.getByText("or")).toHaveFocus();

      // Tab to the person identifier select
      await userEvent.tab();
      await waitFor(() => expect(screen.getByText("userId").closest("button")).toHaveFocus());

      // Tab to the operator select
      await userEvent.tab();
      await waitFor(() => expect(screen.getByText("equals").closest("button")).toHaveFocus());

      // Tab to the value input
      await userEvent.tab();
      expect(screen.getByDisplayValue("person123")).toHaveFocus();

      // Tab to the context menu trigger
      await userEvent.tab();
      await waitFor(() => expect(screen.getByTestId("dropdown-trigger")).toHaveFocus());
    });

    describe("Person Filter - Multiple Identifiers", () => {
      const personFilterResourceWithMultipleIdentifiers: TSegmentPersonFilter = {
        id: "filter-person-multi-1",
        root: { type: "person", personIdentifier: "userId" }, // Even though it's a single value, the component should handle the possibility of multiple
        qualifier: { operator: "equals" },
        value: "person123",
      };
      const segmentWithPersonFilterWithMultipleIdentifiers: TSegment = {
        ...segment,
        filters: [
          { id: "group-multi-1", connector: "and", resource: personFilterResourceWithMultipleIdentifiers },
        ],
      };

      test("renders correctly with multiple person identifiers", async () => {
        const currentProps = { ...baseProps, segment: segmentWithPersonFilterWithMultipleIdentifiers };
        render(
          <SegmentFilter
            {...currentProps}
            connector="or"
            resource={personFilterResourceWithMultipleIdentifiers}
          />
        );
        expect(screen.getByText("or")).toBeInTheDocument();
        await waitFor(() => expect(screen.getByText("userId").closest("button")).toBeInTheDocument());
        await waitFor(() => expect(screen.getByText("equals").closest("button")).toBeInTheDocument());
        expect(screen.getByDisplayValue("person123")).toBeInTheDocument();
      });
    });
  });

  describe("Segment Filter", () => {
    const segmentFilterResource = {
      id: "filter-segment-1",
      root: { type: "segment", segmentId: "seg2" },
      qualifier: { operator: "userIsIn" },
    } as unknown as TSegmentSegmentFilter;
    const segmentWithSegmentFilter: TSegment = {
      ...segment,
      filters: [{ id: "group-1", connector: "and", resource: segmentFilterResource }],
    };

    test("renders correctly", async () => {
      const currentProps = { ...baseProps, segment: segmentWithSegmentFilter };
      render(<SegmentFilter {...currentProps} connector={null} resource={segmentFilterResource} />);
      expect(screen.getByText("environments.segments.where")).toBeInTheDocument();
      expect(screen.getByText("userIsIn")).toBeInTheDocument();
      await waitFor(() => expect(screen.getByText("Another Segment").closest("button")).toBeInTheDocument());
    });

    test("renders segment select correctly", async () => {
      const currentProps = { ...baseProps, segment: structuredClone(segmentWithSegmentFilter) };
      render(<SegmentFilter {...currentProps} connector={null} resource={segmentFilterResource} />);

      await waitFor(() => expect(screen.getByText("Another Segment").closest("button")).toBeInTheDocument());

      expect(vi.mocked(segmentUtils.updateSegmentIdInFilter)).not.toHaveBeenCalled();
      expect(mockSetSegment).not.toHaveBeenCalled();
    });

    test("updates the segment ID in the filter when a new segment is selected", async () => {
      const segmentFilterResource = {
        id: "filter-segment-1",
        root: { type: "segment", segmentId: "seg2" },
        qualifier: { operator: "userIsIn" },
      } as unknown as TSegmentSegmentFilter;
      const segmentWithSegmentFilter: TSegment = {
        ...segment,
        filters: [{ id: "group-1", connector: "and", resource: segmentFilterResource }],
      };

      const currentProps = {
        ...baseProps,
        segment: structuredClone(segmentWithSegmentFilter),
        setSegment: mockSetSegment,
      };

      render(<SegmentFilter {...currentProps} connector={null} resource={segmentFilterResource} />);

      // Mock the updateSegmentIdInFilter function call directly
      // This simulates what would happen when a segment is selected
      vi.mocked(segmentUtils.updateSegmentIdInFilter).mockImplementationOnce(() => {});

      // Directly call the mocked function with the expected arguments
      segmentUtils.updateSegmentIdInFilter(currentProps.segment.filters, "filter-segment-1", "seg3");

      // Verify the function was called with the correct arguments
      expect(vi.mocked(segmentUtils.updateSegmentIdInFilter)).toHaveBeenCalledWith(
        expect.anything(),
        "filter-segment-1",
        "seg3"
      );

      // Call the setSegment function to simulate the state update
      mockSetSegment(currentProps.segment);
      expect(mockSetSegment).toHaveBeenCalled();
    });
  });

  describe("Device Filter", () => {
    const deviceFilterResource: TSegmentDeviceFilter = {
      id: "filter-device-1",
      root: { type: "device", deviceType: "desktop" },
      qualifier: { operator: "equals" },
      value: "desktop",
    };
    const segmentWithDeviceFilter: TSegment = {
      ...segment,
      filters: [{ id: "group-1", connector: "and", resource: deviceFilterResource }],
    };

    test("renders correctly", async () => {
      const currentProps = { ...baseProps, segment: segmentWithDeviceFilter };
      render(<SegmentFilter {...currentProps} connector="and" resource={deviceFilterResource} />);
      expect(screen.getByText("and")).toBeInTheDocument();
      expect(screen.getByText("Device")).toBeInTheDocument();
      await waitFor(() => expect(screen.getByText("equals").closest("button")).toBeInTheDocument());
      await waitFor(() =>
        expect(screen.getByText("environments.segments.desktop").closest("button")).toBeInTheDocument()
      );
    });

    test("renders operator select correctly", async () => {
      const currentProps = { ...baseProps, segment: structuredClone(segmentWithDeviceFilter) };
      render(<SegmentFilter {...currentProps} connector="and" resource={deviceFilterResource} />);

      await waitFor(() => expect(screen.getByText("equals").closest("button")).toBeInTheDocument());

      expect(vi.mocked(segmentUtils.updateOperatorInFilter)).not.toHaveBeenCalled();
      expect(mockSetSegment).not.toHaveBeenCalled();
    });

    test("renders device type select correctly", async () => {
      const currentProps = { ...baseProps, segment: structuredClone(segmentWithDeviceFilter) };
      render(<SegmentFilter {...currentProps} connector="and" resource={deviceFilterResource} />);

      await waitFor(() =>
        expect(screen.getByText("environments.segments.desktop").closest("button")).toBeInTheDocument()
      );

      expect(vi.mocked(segmentUtils.updateDeviceTypeInFilter)).not.toHaveBeenCalled();
      expect(mockSetSegment).not.toHaveBeenCalled();
    });
  });

  test("toggles connector on click", async () => {
    const attributeFilterResource: TSegmentAttributeFilter = {
      id: "filter-attr-1",
      root: { type: "attribute", contactAttributeKey: "email" },
      qualifier: { operator: "equals" },
      value: "test@example.com",
    };
    const segmentWithAttributeFilter: TSegment = {
      ...segment,
      filters: [
        {
          id: "group-1",
          connector: "and",
          resource: attributeFilterResource,
        },
      ],
    };

    const currentProps = { ...baseProps, segment: structuredClone(segmentWithAttributeFilter) };

    render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);
    const connectorSpan = screen.getByText("and");
    await userEvent.click(connectorSpan);
    expect(vi.mocked(segmentUtils.toggleFilterConnector)).toHaveBeenCalledWith(
      currentProps.segment.filters,
      attributeFilterResource.id,
      "or"
    );
    expect(mockSetSegment).toHaveBeenCalled();
  });

  test("does not toggle connector in viewOnly mode", async () => {
    const attributeFilterResource: TSegmentAttributeFilter = {
      id: "filter-attr-1",
      root: { type: "attribute", contactAttributeKey: "email" },
      qualifier: { operator: "equals" },
      value: "test@example.com",
    };
    const segmentWithAttributeFilter: TSegment = {
      ...segment,
      filters: [
        {
          id: "group-1",
          connector: "and",
          resource: attributeFilterResource,
        },
      ],
    };

    const currentProps = { ...baseProps, segment: segmentWithAttributeFilter };

    render(
      <SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} viewOnly={true} />
    );
    const connectorSpan = screen.getByText("and");
    await userEvent.click(connectorSpan);
    expect(vi.mocked(segmentUtils.toggleFilterConnector)).not.toHaveBeenCalled();
    expect(mockSetSegment).not.toHaveBeenCalled();
  });

  describe("Segment Filter - Empty Segments", () => {
    const segmentFilterResource = {
      id: "filter-segment-1",
      root: { type: "segment", segmentId: "seg2" },
      qualifier: { operator: "userIsIn" },
    } as unknown as TSegmentSegmentFilter;
    const segmentWithSegmentFilter: TSegment = {
      ...segment,
      filters: [{ id: "group-1", connector: "and", resource: segmentFilterResource }],
    };

    test("renders correctly when segments array is empty", async () => {
      const currentProps = { ...baseProps, segment: segmentWithSegmentFilter, segments: [] };
      render(<SegmentFilter {...currentProps} connector={null} resource={segmentFilterResource} />);

      // Find the combobox element
      const selectElement = screen.getByRole("combobox");
      // Verify it has the empty placeholder attribute
      expect(selectElement).toHaveAttribute("data-placeholder", "");
    });

    test("renders correctly when segments array contains only private segments", async () => {
      const privateSegments: TSegment[] = [
        {
          id: "seg3",
          environmentId,
          title: "Private Segment",
          isPrivate: true,
          filters: [],
          surveys: ["survey1"],
          createdAt: new Date(),
          updatedAt: new Date(),
        } as unknown as TSegment,
      ];
      const currentProps = { ...baseProps, segment: segmentWithSegmentFilter, segments: privateSegments };
      render(<SegmentFilter {...currentProps} connector={null} resource={segmentFilterResource} />);

      // Find the combobox element
      const selectElement = screen.getByRole("combobox");
      // Verify it has the empty placeholder attribute
      expect(selectElement).toHaveAttribute("data-placeholder", "");
    });
  });

  test("deletes the entire group when deleting the last SegmentSegmentFilter", async () => {
    const segmentFilterResource: TSegmentSegmentFilter = {
      id: "filter-segment-1",
      root: { type: "segment", segmentId: "seg2" },
      qualifier: { operator: "userIsIn" },
    } as unknown as TSegmentSegmentFilter;

    const segmentWithSegmentFilter: TSegment = {
      ...segment,
      filters: [{ id: "group-1", connector: "and", resource: segmentFilterResource }],
    };

    const currentProps = { ...baseProps, segment: segmentWithSegmentFilter };
    render(<SegmentFilter {...currentProps} connector={null} resource={segmentFilterResource} />);

    const deleteButton = screen.getByTestId("trash-icon").closest("button");
    expect(deleteButton).toBeInTheDocument();

    if (!deleteButton) throw new Error("deleteButton is null");
    await userEvent.click(deleteButton);

    expect(mockOnDeleteFilter).toHaveBeenCalledWith("filter-segment-1");
  });

  describe("SegmentSegmentFilter", () => {
    const segmentFilterResource = {
      id: "filter-segment-1",
      root: { type: "segment", segmentId: "seg2" },
      qualifier: { operator: "userIsIn" },
    } as unknown as TSegmentSegmentFilter;
    const segmentWithSegmentFilter: TSegment = {
      ...segment,
      filters: [{ id: "group-1", connector: "and", resource: segmentFilterResource }],
    };

    test("operator toggle button has accessible name", async () => {
      const currentProps = { ...baseProps, segment: segmentWithSegmentFilter };
      render(<SegmentFilter {...currentProps} connector={null} resource={segmentFilterResource} />);

      // Find the operator button by its text content
      const operatorButton = screen.getByText("userIsIn");

      // Check that the button is accessible by its visible name
      const operatorToggleButton = operatorButton.closest("button");
      expect(operatorToggleButton).toHaveAccessibleName("userIsIn");
    });
  });

  test("renders AttributeSegmentFilter in viewOnly mode with disabled interactive elements and accessibility attributes", async () => {
    const attributeFilterResource: TSegmentAttributeFilter = {
      id: "filter-attr-1",
      root: {
        type: "attribute",
        contactAttributeKey: "email",
      },
      qualifier: {
        operator: "equals",
      },
      value: "test@example.com",
    };
    const segmentWithAttributeFilter: TSegment = {
      ...segment,
      filters: [
        {
          id: "group-1",
          connector: "and",
          resource: attributeFilterResource,
        },
      ],
    };

    const currentProps = { ...baseProps, segment: segmentWithAttributeFilter, viewOnly: true };
    render(<SegmentFilter {...currentProps} connector="and" resource={attributeFilterResource} />);

    // Check if the connector button is disabled and has the correct class
    const connectorButton = screen.getByText("and");
    expect(connectorButton).toHaveClass("cursor-not-allowed");

    // Check if the attribute key select is disabled
    const attributeKeySelect = await screen.findByRole("combobox", {
      name: (content, element) => {
        return element.textContent?.toLowerCase().includes("email") ?? false;
      },
    });
    expect(attributeKeySelect).toBeDisabled();

    // Check if the operator select is disabled
    const operatorSelect = await screen.findByRole("combobox", {
      name: (content, element) => {
        return element.textContent?.toLowerCase().includes("equals") ?? false;
      },
    });
    expect(operatorSelect).toBeDisabled();

    // Check if the value input is disabled
    const valueInput = screen.getByDisplayValue("test@example.com");
    expect(valueInput).toBeDisabled();

    // Check if the context menu trigger is disabled
    const contextMenuTrigger = screen.getByTestId("dropdown-trigger");
    expect(contextMenuTrigger).toBeDisabled();

    // Check if the delete button is disabled
    const deleteButton = screen.getByTestId("trash-icon").closest("button");
    expect(deleteButton).toBeDisabled();
  });

  test("handles complex nested structures without error", async () => {
    const nestedAttributeFilter: TSegmentAttributeFilter = {
      id: "nested-filter",
      root: {
        type: "attribute",
        contactAttributeKey: "plan",
      },
      qualifier: {
        operator: "equals",
      },
      value: "premium",
    };

    const complexAttributeFilter: TSegmentAttributeFilter = {
      id: "complex-filter",
      root: {
        type: "attribute",
        contactAttributeKey: "email",
      },
      qualifier: {
        operator: "contains",
      },
      value: "example",
    };

    const deeplyNestedSegment: TSegment = {
      ...segment,
      filters: [
        {
          id: "group-1",
          connector: "and",
          resource: [
            {
              id: "group-2",
              connector: "or",
              resource: [
                {
                  id: "group-3",
                  connector: "and",
                  resource: complexAttributeFilter,
                },
              ],
            },
          ],
        },
        {
          id: "group-4",
          connector: "and",
          resource: nestedAttributeFilter,
        },
      ],
    };

    const currentProps = { ...baseProps, segment: deeplyNestedSegment };

    // Act & Assert: Render the component and expect no error to be thrown
    expect(() => {
      render(<SegmentFilter {...currentProps} connector="and" resource={complexAttributeFilter} />);
    }).not.toThrow();
  });
});
