import * as React from "react";
import { render, fireEvent, cleanup, screen } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import Editor from "./Editor";
import { ComponentTypes } from "@sc/plugins/webcomponents/v2/types";

import { sampleContentData } from "./module.stories";

const components = Object.keys(ComponentTypes);

describe("Editor (Rendering)", () => {
  afterEach(cleanup);

  it(`Should show editor in the dom`, () => {
    const { getByTestId } = render(
      <Editor
        name="Editor"
        content={sampleContentData}
        components={components}
      />
    );
    expect(getByTestId("Editor-Default")).not.toBe(null);
  });

  it(`Should show the same number of items in the dom as there are items in the content prop`, () => {
    const { queryAllByTestId } = render(
      <Editor
        name="Editor"
        content={sampleContentData}
        components={components}
      />
    );

    expect(queryAllByTestId("Editor-EditorObject-Item").length).toEqual(
      sampleContentData.length
    );
  });

  it(`Should show items in the dom as specific in the content prop and match components found in the components prop`, () => {
    const { debug, queryAllByTestId } = render(
      <Editor
        name="Editor"
        content={sampleContentData}
        components={components}
      />
    );

    sampleContentData.forEach((itm) => {
      expect(queryAllByTestId(`WC-${itm.type}-EDIT`)).not.toBe(null);
    });
  });

  it(`Should show a default drag handle component near each object when selected`, () => {
    const { debug, queryAllByTestId } = render(
      <Editor
        name="Editor"
        content={sampleContentData}
        components={components}
      />
    );

    expect(queryAllByTestId(`Editor-EditorObject`).length).toEqual(
      sampleContentData.length
    );
  });

  it(`Should show an item legend if the itemLegendIsVisible prop is true`, () => {
    const { getByTestId } = render(
      <Editor
        name="Editor"
        content={sampleContentData}
        components={components}
        itemLegendIsVisible
      />
    );
    expect(getByTestId("Editor-ItemLegend")).not.toBe(false);
  });

  it(`Props in the item legend should match the object provided in the itemLegendSettings prop`, () => {
    const title = "Item Legend Title!";

    const { getByText } = render(
      <Editor
        name="Editor"
        content={sampleContentData}
        components={components}
        itemLegendIsVisible
        itemLegendSettings={{
          title,
        }}
      />
    );

    expect(getByText(title)).not.toBe(false);
  });

  // // it(`Should show a wrapper component around each object in the dom`, () => {
  // //   expect(true).toBe(false);
  // // });

  // it(`Should keep track of the changes that occur in the content prop via the undoStack prop`, () => {
  //   expect(true).toBe(false);
  // });

  // it(`Should keep track of the current undo position in the undoPosition prop.  Number decrements on undo actions, increments on redo.`, () => {
  //   expect(true).toBe(false);
  // });

  test.todo(
    `Should only be able to drag section objects up and down if dragMode prop is set to BLOCK`
  );

  test.skip(`Should not be able to add new items if canAddItems prop is false`, () => {});

  test.skip(`Should not be able to drag items if canDrag prop is false`, () => {});

  test.skip(`Should be able to move items one pixel at a time if dragMode prop is set to PIXELBYPIXEL`, () => {});

  test.skip(`Should show a snap guide if in PIXELBYPIXEL mode and dragging an object next to the vertical or horizontal cross-section of another object`, () => {});

  test.skip(`Should show a custom cursor component when one is provided in the cursorComponent prop`, () => {});

  test.skip(`Should show a custom wrapper component around each object when a custom component is provided in the editorObjectComponent prop`, () => {});

  test.skip(`Should modify the editor object (e.g. colors, etc.) according to the editorObjectSettings prop`, () => {});

  test.skip(`Should show a custom drag handle component near each object when selected and a custom component is provided in the dragHandleComponent prop`, () => {});

  test.skip(`Should modify the drag handle (e.g. colors, etc.) according to the dragHandleSettings prop`, () => {});

  test.skip(`Should show a custom resize handler component for resizable editor objects when one is provided in the resizeHandleComponent prop`, () => {});

  test.skip(`Should modify the resize handler (e.g. colors, etc.) according to the resizeHandlerSettings prop`, () => {});

  test.skip(`Should not allow any changes of any kind when the readOnly prop is set to true`, () => {});

  test.skip(`Should show editor component in a zoomed state the corresponds with the number in the zoom prop`, () => {});

  test.skip(`Should show the component provided in the itemLegendComponent prop instead of the default one if one is provided`, () => {});
});

describe("Editor (Actions)", () => {
  afterEach(cleanup);

  const Edtr = (
    <Editor name="Editor" content={sampleContentData} component={components} />
  );
  it("Should change the state when I hover over it", () => {
    const { queryAllByTestId, debug } = render(Edtr);
    fireEvent.mouseEnter(queryAllByTestId("Editor-EditorObject")[0]);
    expect(queryAllByTestId("Editor-EditorObject-State-Hover")).not.toBe(null);
  });

  it("Should change the state when I hover away from it", () => {
    const stateId = "Editor-EditorObject-State-Hover";
    const { debug, queryAllByTestId } = render(Edtr);
    fireEvent.mouseEnter(queryAllByTestId("Editor-EditorObject")[1]);
    expect(queryAllByTestId(stateId).length).toEqual(1);
    fireEvent.mouseLeave(queryAllByTestId("Editor-EditorObject")[1]);
    expect(queryAllByTestId(stateId).length).toEqual(0);
  });

  it("Should change the state when I click on it", () => {
    const stateId = "Editor-EditorObject-State-Active";
    const { debug, queryAllByTestId } = render(Edtr);
    expect(queryAllByTestId(stateId).length).toEqual(0);
    fireEvent.click(queryAllByTestId("Editor-EditorObject")[1]);
    expect(queryAllByTestId(stateId).length).toEqual(1);
  });

  it("Should not clear the state if active when i hover away from it", () => {
    const hoverId = "Editor-EditorObject-State-Hover";
    const activeId = "Editor-EditorObject-State-Active";
    // Render the editor
    const { debug, queryAllByTestId } = render(Edtr);

    // Make the mouse enter the second object
    fireEvent.mouseEnter(queryAllByTestId("Editor-EditorObject")[1]);
    expect(queryAllByTestId(hoverId).length).toEqual(1);

    // Make the mouse leave the second object
    fireEvent.mouseLeave(queryAllByTestId("Editor-EditorObject")[1]);
    expect(queryAllByTestId(hoverId).length).toEqual(0);

    // Click the second object
    fireEvent.click(queryAllByTestId("Editor-EditorObject")[1]);
    expect(queryAllByTestId(activeId).length).toEqual(1);

    // Make the mouse leave the second object
    fireEvent.mouseLeave(queryAllByTestId("Editor-EditorObject")[1]);

    // The state should remain active
    expect(queryAllByTestId(activeId).length).toEqual(1);
  });

  it("Should clear the state of all others when i click on it", () => {
    const activeId = "Editor-EditorObject-State-Active";
    const normalId = "Editor-EditorObject-State-Normal";
    const editorObjectId = "Editor-EditorObject";

    // render the editor
    const { debug, queryAllByTestId } = render(Edtr);

    // click the first object
    fireEvent.click(queryAllByTestId(editorObjectId)[0]);
    expect(queryAllByTestId(activeId).length).toEqual(1);

    // click the second object
    fireEvent.click(queryAllByTestId(editorObjectId)[1]);
    expect(queryAllByTestId(activeId).length).toEqual(1);

    // confirm that the first object no longer has an active state
    expect(
      queryAllByTestId(editorObjectId)[0].firstChild.getAttribute("data-testid")
    ).toBe(normalId);
    // debug();
  });

  // it(`Should show a cursor when dragging items around in OBJECT mode`, () => {
  //   expect(true).toBe(false);
  // });

  // it(`Should only be able to move items above, beneath, and inside existing objects if dragMode prop is set to OBJECT`, () => {
  //   expect(true).toBe(false);
  // });

  test.skip(`Should be able to open an objects property (if provided) when I double click on it`, () => {});

  test.skip(`Should be able to remove items via [delete] on my keyboard`, () => {});

  test.skip(`Should be able to duplicate an item by pressing [CTRL/CMD] + [D] on my keyboard`, () => {});

  test.skip(`Should be able to replace the content in the editor through the updateContent method`, () => {});

  test.skip(`Should be able to change the style properties of an item in the editor through the updateComponentStyle method`, () => {});

  test.skip(`Should be able to update anything about an item through the updateComponentSettings method`, () => {});
});

describe("Editor (Methods)", () => {
  test.skip(`Should trigger the addThisAfterThat() method when an item is to be added to the editor`, () => {});

  test.skip(`Should trigger the removeItem() method when an item should be removed from the content array`, () => {});

  test.skip(`Should trigger the duplicateItem() method when an item should be duplicated`, () => {});

  test.skip(`Should trigger the moveThisByThat() method when an item should be moved to another location`, () => {});

  test.skip(`Should trigger the updateContent() method when the editor's content should be updated`, () => {});

  test.skip(`Should trigger the updateComponentStyle() method when an items style should be changed`, () => {});

  test.skip(`Should trigger the updateComponentSettings() method when something should change about an item`, () => {});

  test.skip(`Should trigger the setActiveObject() method when an item's state should be active`, () => {});

  test.skip(`Should trigger the doUndoRedo() method when the editor's content needs to return to a previous state`, () => {});

  test.skip(`Should trigger the chagneState() method when the item's state should change`, () => {});

  test.skip(`Should be able to enable or disable the editors canDrag property from anywhere in the editor`, () => {});

  test.skip(`Should be able to retrieve a list of all the direct ancestors to a provided editor item from anywhere inside the editor`, () => {});

  test.skip(`Should be able to retrieve a list of the items (and a useful icon) in the editor using the listComponents method from anywhere inside the editor`, () => {});
});

describe("Editor (Events)", () => {
  test.skip(`Should trigger onAdd() event with appropriate payload when a new item is added to the editor`, () => {});

  test.skip(`Should trigger onRemove() event with appropriate payload when an item is removed from the editor`, () => {});

  test.skip(`Should trigger onDuplicate() event with appropriate payload when an item is duplicated in the editor`, () => {});

  test.skip(`Should trigger onMove() event with appropriate payload when an item is moved in the editor`, () => {});

  test.skip(`Should trigger onStateChange() event with appropriate payload when the state of an item changes in the editor`, () => {});

  test.skip(`Should trigger onChange() event with appropriate payload when an item in the editor changes in some way`, () => {});

  test.skip(`Should trigger onKeyUp() event with appropriate payload when a key is pressed in the editor`, () => {});

  test.skip(`Should trigger onSelect() event with appropriate payload when an item is selected in the editor`, () => {});

  test.skip(`Should trigger onUndo() event with appropriate payload when an undo action is supposed to happen`, () => {});

  test.skip(`Should trigger onRedo() event with appropriate payload when redo action is supposed to happen`, () => {});
});

describe("Editor (Hooks)", () => {
  test.skip(`Hooks: Should trigger _onAddItem_ hook when a new item is added to the editor`, () => {});

  test.skip(`Hooks: Should trigger _onRemoveItem_ hook when an item is removed from the editor`, () => {});

  test.skip(`Hooks: Should trigger _onDuplicateItem_ hook when an item is duplicated in the editor`, () => {});

  test.skip(`Hooks: Should trigger _onMoveItem_ hook when an item is duplicated in the editor`, () => {});

  test.skip(`Hooks: Should trigger _onResizeItem_ hook when an item is resizing in the editor`, () => {});

  test.skip(`Hooks: Should trigger _onResizeItemEnd_ hook when an item is done resizing itself`, () => {});

  test.skip(`Hooks: Should trigger _onItemStateChange_ hook when the state of an item changes in the editor`, () => {});

  test.skip(`Hooks: Should trigger _onChange_ hook when an item in the editor changes in some way`, () => {});

  test.skip(`Hooks: Should trigger _onKeyUp_ hook when a key is pressed in the editor`, () => {});

  test.skip(`Hooks: Should trigger _onSelectItem_ hook when an item is selected in the editor`, () => {});

  test.skip(`Hooks: Should trigger _onUndo_ hook when an undo action is supposed to happen`, () => {});

  test.skip(`Hooks: Should trigger _onRedo_ hook when redo action is supposed to happen`, () => {});

  test.skip(`Hooks: Should trigger _onEditorRender_ hook when Editor is rendered`, () => {});

  test.skip(`Hooks: Should trigger _onEditorObjectRender_ hook when Editor Object is rendered`, () => {});

  test.skip(`Hooks: Should trigger _onComponentLoaderRender_ hook when the Component Loader is rendered`, () => {});

  test.skip(`Hooks: Should trigger _onWebComponentWrapperRender_ hook when componentWrapper is rendered`, () => {});
});
