import { providePlugins, proxy, xml } from "@odoo/owl";
import { BorderPosition, BorderStyle, Color, Model } from "../../src";
import { BorderEditorWidget } from "../../src/components/border_editor/border_editor_widget";
import { PopoverContainerPlugin } from "../../src/components/popover/popover_container_owl_plugin";
import { toHex } from "../../src/helpers/color";
import { toZone } from "../../src/helpers/zones";
import { Component } from "../../src/owl3_compatibility_layer";
import { PropsOf } from "../../src/types/props_of";
import { SpreadsheetChildEnv } from "../../src/types/spreadsheet_env";
import { click, simulateClick } from "../test_helpers/dom_helper";
import { mountComponent } from "../test_helpers/helpers";
import { extendMockGetBoundingClientRect } from "../test_helpers/mock_helpers";

let fixture: HTMLElement;
let model: Model;

async function setBorder({
  position,
  color,
  style,
}: {
  position: BorderPosition;
  color?: Color;
  style?: BorderStyle;
}) {
  if (position !== "clear") {
    if (color) {
      await simulateClick('div[title="Border color"]');
      await simulateClick(`div[data-color="${color}"]`);
    }
    if (style) {
      await simulateClick('div[title="Line style"]');
      await simulateClick(`div[title="${style}"]`);
    }
  }
  await simulateClick(`.o-line-item[name="${position}"]`);
}

class BorderWidgetContainer extends Component<SpreadsheetChildEnv> {
  static template = xml/* xml */ `
    <div class="o-spreadsheet">
      <div class="container">
        <BorderEditorWidget t-props="this.borderWidgetProps"/>
      </div>
    </div>
  `;
  static components = { BorderEditorWidget };
  state!: { showBorderEditor: boolean };

  setup() {
    this.state = proxy({
      showBorderEditor: false,
    });

    providePlugins([PopoverContainerPlugin], {
      getPopoverContainerRect: () => ({ x: 0, y: 0, height: 1000, width: 1000 }),
    });
  }

  get borderWidgetProps(): PropsOf<BorderEditorWidget> {
    return { class: "border-widget" };
  }
}

async function mountBorderWidgetContainer() {
  ({ fixture, model } = await mountComponent(BorderWidgetContainer));
}

extendMockGetBoundingClientRect({
  "border-widget": () => ({ x: 10, y: 10, width: 300, height: 300 }),
  "o-spreadsheet": () => ({ x: 0, y: 0, width: 1000, height: 1000 }),
});

describe("BorderEditorWidget", () => {
  test("Clicking the widget toggles the border editor", async () => {
    await mountBorderWidgetContainer();
    expect(fixture.querySelector(".o-border-selector")).toBeNull();
    await simulateClick(".border-widget");
    expect(fixture.querySelector(".o-border-selector")).not.toBeNull();
    await simulateClick(".border-widget");
    expect(fixture.querySelector(".o-border-selector")).toBeNull();
  });

  test("The border style and color are persistent when toggling the editor", async () => {
    await mountBorderWidgetContainer();
    const sheetId = model.getters.getActiveSheetId();
    const dispatch = jest.spyOn(model, "dispatch");
    await simulateClick(".border-widget");
    await setBorder({ position: "all", color: toHex("#ff0000"), style: "dashed" });
    expect(dispatch).toHaveBeenCalledWith("SET_ZONE_BORDERS", {
      border: { color: "#FF0000", position: "all", style: "dashed" },
      sheetId,
      target: [toZone("A1")],
    });
    // close the menu
    await simulateClick(".border-widget");
    expect(fixture.querySelector(".o-border-selector") as HTMLElement).toBeNull();
    // reopen the menu
    await simulateClick(".border-widget");
    await setBorder({ position: "external" });
    expect(dispatch).toHaveBeenCalledWith("SET_ZONE_BORDERS", {
      border: { color: "#FF0000", position: "external", style: "dashed" },
      sheetId,
      target: [toZone("A1")],
    });
  });

  test("The border position is reset when toggling the editor", async () => {
    await mountBorderWidgetContainer();
    const sheetId = model.getters.getActiveSheetId();
    const dispatch = jest.spyOn(model, "dispatch");
    await simulateClick(".border-widget");
    await click(fixture, 'span[name="all"]');
    expect(dispatch).toHaveBeenCalledWith("SET_ZONE_BORDERS", {
      border: { color: "#000000", position: "all", style: "thin" },
      sheetId,
      target: [toZone("A1")],
    });
    expect(fixture.querySelector('span[name="all"].active')).not.toBeNull();

    // close the menu
    await simulateClick(".border-widget");
    // reopen the menu
    await simulateClick(".border-widget");
    expect(fixture.querySelector('span[name="all"].active')).toBeNull();
  });
});
