import React from "react";
import { test, expect } from "./utils/coverage";
import { MetadataCellEditor } from "../src/components/metadata/editors/MetadataCellEditor";
import { MetadataDataType } from "../src/types/metadata";
import { createMockColumn } from "./factories/metadataFactories";
import { docScreenshot } from "./utils/docScreenshot";

test.describe("MetadataCellEditor", () => {
  test("renders string editor", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.STRING,
      validationRules: { max_length: 50 },
    });

    const handleChange = () => {};

    await mount(
      <MetadataCellEditor
        column={column}
        value="Initial value"
        onChange={handleChange}
      />
    );

    const input = page.getByRole("textbox");
    await expect(input).toBeVisible();
    await expect(input).toHaveValue("Initial value");

    await docScreenshot(page, "metadata--cell-editor--string-input");

    // Test that max length is enforced
    await input.fill("a".repeat(60)); // Try to enter 60 characters
    const value = await input.inputValue();
    expect(value.length).toBeLessThanOrEqual(50); // Should be truncated to 50
  });

  test("renders text editor (textarea)", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.TEXT,
    });

    await mount(
      <MetadataCellEditor
        column={column}
        value={"Multi\nline\ntext"}
        onChange={() => {}}
      />
    );

    const textarea = page.getByRole("textbox");
    await expect(textarea).toBeVisible();
    await expect(textarea).toHaveValue("Multi\nline\ntext");
    await expect(textarea.evaluate((el) => el.tagName)).resolves.toBe(
      "TEXTAREA"
    );
  });

  test("renders number editor", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.NUMBER,
      validationRules: { min_value: 0, max_value: 100 },
    });

    await mount(
      <MetadataCellEditor column={column} value={50} onChange={() => {}} />
    );

    const input = page.getByRole("spinbutton");
    await expect(input).toBeVisible();
    await expect(input).toHaveAttribute("type", "number");
    await expect(input).toHaveValue("50");

    // Test that validation constraints work
    // Note: Browser number inputs may not strictly enforce min/max on typing
    // but the component should validate the values
  });

  test("renders boolean editor (checkbox)", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.BOOLEAN,
    });

    await mount(
      <MetadataCellEditor column={column} value={true} onChange={() => {}} />
    );

    const checkbox = page.getByRole("checkbox");
    await expect(checkbox).toBeVisible();
    await expect(checkbox).toBeChecked();

    await docScreenshot(page, "metadata--cell-editor--boolean-checkbox");
  });

  test("renders date editor", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.DATE,
      validationRules: {
        min_date: "2024-01-01",
        max_date: "2024-12-31",
      },
    });

    await mount(
      <MetadataCellEditor
        column={column}
        value="2024-06-15"
        onChange={() => {}}
      />
    );

    const input = page.getByRole("textbox");
    await expect(input).toBeVisible();
    await expect(input).toHaveAttribute("type", "date");
    await expect(input).toHaveValue("2024-06-15");

    // Test the functionality works even if attributes aren't set
    // Date inputs should respect min/max constraints
  });

  test("renders select editor for choices", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.STRING,
      validationRules: {
        choices: ["Option A", "Option B", "Option C"],
      },
    });

    await mount(
      <MetadataCellEditor
        column={column}
        value="Option B"
        onChange={() => {}}
      />
    );

    const dropdown = page.locator(".oc-dropdown").first();
    await expect(dropdown).toBeVisible();
    // Should show the selected value
    await expect(dropdown.locator(".oc-dropdown__value")).toHaveText(
      "Option B"
    );

    // Click to open the dropdown and check the options
    await dropdown.locator(".oc-dropdown__trigger").click();

    const options = page.locator(".oc-dropdown__option");
    await expect(options).toHaveCount(3);
    await expect(options.nth(0)).toContainText("Option A");
    await expect(options.nth(1)).toContainText("Option B");
    await expect(options.nth(2)).toContainText("Option C");

    await docScreenshot(page, "metadata--cell-editor--select-dropdown");
  });

  test("renders JSON editor", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.JSON,
    });

    const jsonValue = { key: "value", nested: { a: 1 } };

    await mount(
      <MetadataCellEditor
        column={column}
        value={jsonValue}
        onChange={() => {}}
      />
    );

    const textarea = page.getByRole("textbox");
    await expect(textarea).toBeVisible();
    await expect(textarea).toHaveValue(JSON.stringify(jsonValue, null, 2));
  });

  test("shows validation feedback in real-time", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.NUMBER,
      validationRules: { min_value: 0, max_value: 100 },
    });

    let validationState = true;
    const handleValidationChange = (isValid: boolean) => {
      validationState = isValid;
    };

    const component = await mount(
      <MetadataCellEditor
        column={column}
        value={50}
        onChange={() => {}}
        onValidationChange={handleValidationChange}
      />
    );

    const input = page.getByRole("spinbutton");

    // Valid value - should show success
    await input.fill("75");
    await component.update(
      <MetadataCellEditor
        column={column}
        value={75}
        onChange={() => {}}
        onValidationChange={handleValidationChange}
      />
    );
    await page.waitForTimeout(100); // Give time for icon to render
    // Semantic UI icons have aria-hidden="true" which makes them technically "hidden" to screen readers
    // But they should still be visually present in the DOM
    await expect(page.getByTestId("validation-icon-success")).toHaveCount(1);

    // Invalid value - should show error
    await input.fill("150");
    await component.update(
      <MetadataCellEditor
        column={column}
        value={150}
        onChange={() => {}}
        onValidationChange={handleValidationChange}
      />
    );
    await page.waitForTimeout(100); // Give time for icon to render
    // Semantic UI icons have aria-hidden="true" but should still be in DOM
    await expect(page.getByTestId("validation-icon-error")).toHaveCount(1);
    await expect(page.getByText("Must be ≤ 100")).toBeVisible();

    // Another invalid case
    await input.fill("-10");
    await component.update(
      <MetadataCellEditor
        column={column}
        value={-10}
        onChange={() => {}}
        onValidationChange={handleValidationChange}
      />
    );
    await page.waitForTimeout(100); // Give time for icon to render
    // Semantic UI icons have aria-hidden="true" but should still be in DOM
    await expect(page.getByTestId("validation-icon-error")).toHaveCount(1);
    await expect(page.getByText("Must be ≥ 0")).toBeVisible();
  });

  test("handles onChange callback", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.STRING,
    });

    let capturedValue = "";
    const handleChange = (value: any) => {
      capturedValue = value;
    };

    const component = await mount(
      <MetadataCellEditor column={column} value="" onChange={handleChange} />
    );

    const input = page.getByRole("textbox");
    await input.fill("New value");

    // The component is controlled, so we need to re-render with the new value
    await component.update(
      <MetadataCellEditor
        column={column}
        value={"New value"}
        onChange={handleChange}
      />
    );

    expect(capturedValue).toBe("New value");
  });

  test(
    "handles boolean toggle",
    { timeout: 20000 },
    async ({ mount, page }) => {
      const column = createMockColumn({
        dataType: MetadataDataType.BOOLEAN,
      });

      let capturedValue = false;
      const handleChange = (value: boolean) => {
        capturedValue = value;
      };

      const component = await mount(
        <MetadataCellEditor
          column={column}
          value={false}
          onChange={handleChange}
        />
      );

      const checkbox = page.getByRole("checkbox");
      await expect(checkbox).not.toBeChecked();

      // Click the checkbox directly (no longer wrapped in Semantic UI container)
      await checkbox.click();

      // Wait for the onChange to be called
      await page.waitForTimeout(200);
      expect(capturedValue).toBe(true);

      await component.update(
        <MetadataCellEditor
          column={column}
          value={true}
          onChange={handleChange}
        />
      );

      await expect(checkbox).toBeChecked();
    }
  );

  test("validates JSON input", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.JSON,
    });

    const component = await mount(
      <MetadataCellEditor
        column={column}
        value={{}}
        onChange={() => {}}
        onValidationChange={() => {}}
      />
    );

    const textarea = page.getByRole("textbox");

    // Valid JSON
    await textarea.fill('{"valid": "json"}');
    await component.update(
      <MetadataCellEditor
        column={column}
        value={JSON.parse('{"valid": "json"}')}
        onChange={() => {}}
        onValidationChange={() => {}}
      />
    );
    await page.waitForTimeout(100); // Give time for icon to render
    // Semantic UI icons have aria-hidden="true" which makes them technically "hidden" to screen readers
    // But they should still be visually present in the DOM
    await expect(page.getByTestId("validation-icon-success")).toHaveCount(1);

    // Invalid JSON
    await textarea.fill("{invalid json}");
    await component.update(
      <MetadataCellEditor
        column={column}
        value="{invalid json}"
        onChange={() => {}}
        onValidationChange={() => {}}
      />
    );
    // Semantic UI icons have aria-hidden="true" but should still be in DOM
    await expect(page.getByTestId("validation-icon-error")).toHaveCount(1);
    await expect(page.getByTestId("validation-error-message")).toBeVisible();
  });

  test("handles list editor for string arrays", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.STRING,
      extractIsList: true,
      validationRules: {
        choices: ["Tag1", "Tag2", "Tag3", "Tag4"],
        max_items: 3,
      },
    });

    await mount(
      <MetadataCellEditor
        column={column}
        value={["Tag1", "Tag2"]}
        onChange={() => {}}
      />
    );

    // Should render multi-select dropdown
    const multiselect = page.locator(".oc-dropdown").first();
    await expect(multiselect).toBeVisible();

    // Check selected items are displayed as tags in @os-legal/ui dropdown
    await expect(
      multiselect.locator(".oc-dropdown__tag").filter({ hasText: "Tag1" })
    ).toBeVisible();
    await expect(
      multiselect.locator(".oc-dropdown__tag").filter({ hasText: "Tag2" })
    ).toBeVisible();

    await docScreenshot(page, "metadata--cell-editor--multiselect-tags");
  });

  test("respects readOnly prop", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.STRING,
    });

    await mount(
      <MetadataCellEditor
        column={column}
        value="Read only value"
        onChange={() => {}}
        readOnly={true}
      />
    );

    const input = page.getByRole("textbox");
    await expect(input).toBeVisible();
    await expect(input).toHaveAttribute("readonly");
    await expect(input).toHaveValue("Read only value");

    // Try to edit - should not change
    await input.click();
    await page.keyboard.type("New text");
    await expect(input).toHaveValue("Read only value");
  });

  test("handles null/empty values", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.STRING,
    });

    await mount(
      <MetadataCellEditor column={column} value={null} onChange={() => {}} />
    );

    const input = page.getByRole("textbox");
    await expect(input).toBeVisible();
    await expect(input).toHaveValue("");
    await expect(input).toHaveAttribute("placeholder", expect.any(String));
  });

  test("focuses on mount when autoFocus is true", async ({ mount, page }) => {
    const column = createMockColumn({
      dataType: MetadataDataType.STRING,
    });

    await mount(
      <MetadataCellEditor
        column={column}
        value=""
        onChange={() => {}}
        autoFocus={true}
      />
    );

    const input = page.getByRole("textbox");
    await expect(input).toBeFocused();
  });
});
