import ChartableMixin, {
  ChartItem
} from "../../../../lib/ModelMixins/ChartableMixin";
import StubCatalogItem from "../../../../lib/Models/Catalog/CatalogItems/StubCatalogItem";
import CreateModel from "../../../../lib/Models/Definition/CreateModel";
import { BaseModel } from "../../../../lib/Models/Definition/Model";
import TerriaFeature from "../../../../lib/Models/Feature/Feature";
import Terria from "../../../../lib/Models/Terria";
import ChartExpandAndDownloadButtons from "../../../../lib/ReactViews/Custom/Chart/ChartExpandAndDownloadButtons";
import Chart from "../../../../lib/ReactViews/Custom/Chart/FeatureInfoPanelChart";
import ChartCustomComponent, {
  ChartCustomComponentAttributes
} from "../../../../lib/ReactViews/Custom/ChartCustomComponent";
import {
  DomElement,
  ProcessNodeContext
} from "../../../../lib/ReactViews/Custom/CustomComponent";
import mixTraits from "../../../../lib/Traits/mixTraits";
import MappableTraits from "../../../../lib/Traits/TraitsClasses/MappableTraits";
import UrlTraits from "../../../../lib/Traits/TraitsClasses/UrlTraits";

describe("ChartCustomComponent", function () {
  let terria: Terria;

  beforeEach(function () {
    terria = new Terria({
      baseUrl: "./"
    });
  });

  it("correctly creates the chart", () => {
    const component = new TestChartCustomComponent();
    const context: ProcessNodeContext = {
      terria: terria,
      catalogItem: new StubCatalogItem(undefined, terria, undefined),
      feature: new TerriaFeature({})
    };
    const node: DomElement = {
      name: component.name,
      attribs: {
        data: '[["x","y","z"],[1,10,3],[2,15,9],[3,8,12],[5,25,4]]'
      }
    };
    const chart = component.processNode(context, node, [], 0);

    expect(chart).toBeDefined();
    expect(chart?.key).toContain("chart-wrapper");
    expect(chart?.type).toBe("div");

    expect(chart?.props.children).toBeDefined();
    expect(
      chart?.props.children[0].type === ChartExpandAndDownloadButtons
    ).toBeTruthy();
    expect(chart?.props.children[1].type === Chart).toBeTruthy();
  });

  it("creates shareable chart items for the expand menu", function () {
    const TestComponentWithShareableChartItem = class extends TestChartCustomComponent {
      constructShareableCatalogItem = (
        _id: string | undefined,
        context: ProcessNodeContext,
        _sourceReference: BaseModel | undefined
      ) => this.createItemReference(context.catalogItem as any);
    };
    const component = new TestComponentWithShareableChartItem();
    const context: ProcessNodeContext = {
      terria: terria,
      catalogItem: new StubCatalogItem("parent", terria, undefined),
      feature: new TerriaFeature({})
    };
    const node: DomElement = {
      name: component.name,
      attribs: {
        title: "Foo",
        data: '[["x","y","z"],[1,10,3],[2,15,9],[3,8,12],[5,25,4]]',
        sources: "a, b"
      }
    };
    spyOn(component, "constructShareableCatalogItem").and.callThrough();
    component.processNode(context, node, [], 0);

    expect(component.constructShareableCatalogItem).toHaveBeenCalledTimes(2);
    // Make sure the id is dependent on parent, title & source name
    expect(component.constructShareableCatalogItem).toHaveBeenCalledWith(
      "parent:Foo:a",
      jasmine.any(Object),
      undefined
    );
  });
});

class TestChartCustomComponent extends ChartCustomComponent<ChartableMixin.Instance> {
  get name(): string {
    return "test";
  }
  protected constructCatalogItem(
    id: string | undefined,
    context: ProcessNodeContext,
    _sourceReference:
      | import("../../../../lib/Models/Definition/Model").BaseModel
      | undefined
  ) {
    return context.terria
      ? new TestCatalogItem(id, context.terria, undefined)
      : undefined;
  }
  protected setTraitsFromAttrs(
    _item: TestCatalogItem,
    _attrs: ChartCustomComponentAttributes,
    _sourceIndex: number
  ): void {
    return;
  }
}

class TestCatalogItem extends ChartableMixin(
  CreateModel(mixTraits(UrlTraits, MappableTraits))
) {
  get mapItems() {
    return [];
  }
  protected forceLoadMapItems(): Promise<void> {
    return Promise.resolve();
  }
  get chartItems() {
    return [
      {
        item: {} as never,
        id: "zzz",
        name: "zzz",
        categoryName: "ZZZ",
        key: `key-zzz`,
        type: "line",
        xAxis: { name: "Time", scale: "time" },
        points: [{ x: 10, y: 10 }],
        domain: { x: [0, 100], y: [0, 50] },
        units: "time",
        isSelectedInWorkbench: true,
        showInChartPanel: true,
        updateIsSelectedInWorkbench: () => {},
        getColor: () => "#fff",
        pointOnMap: { latitude: -33.8688, longitude: 151.2093 }
      },
      {
        item: {} as never,
        id: "aaa",
        name: "aaa",
        categoryName: "AAA",
        key: `key-aaa`,
        type: "line",
        xAxis: { name: "Time", scale: "time" },
        points: [{ x: 10, y: 10 }],
        domain: { x: [0, 100], y: [0, 50] },
        units: "time",
        isSelectedInWorkbench: true,
        showInChartPanel: true,
        updateIsSelectedInWorkbench: () => {},
        getColor: () => "#fff",
        pointOnMap: { latitude: -37.814, longitude: 144.96332 }
      }
    ] as ChartItem[];
  }
}
