import { ChartCreationContext, Model } from "../../../src";
import {
  GENERAL_CHART_CREATION_CONTEXT,
  getChartConfiguration,
  getChartLegendLabels,
  isChartAxisStacked,
  toChartDataSource,
} from "../../test_helpers/chart_helpers";
import {
  createChart,
  createChartDefinitionFromContext,
  setCellContent,
  updateChart,
} from "../../test_helpers/commands_helpers";
import { createModelFromGrid } from "../../test_helpers/helpers";

describe("line chart", () => {
  test("create line chart from creation context", () => {
    const context: Required<ChartCreationContext> = {
      ...GENERAL_CHART_CREATION_CONTEXT,
      ...toChartDataSource({
        dataSets: [{ dataRange: "Sheet1!B1:B4", yAxisId: "y1" }],
        labelRange: "Sheet1!A1:A4",
        dataSetsHaveTitle: true,
      }),
    };
    const definition = createChartDefinitionFromContext("line", context);
    expect(definition).toEqual({
      type: "line",
      background: "#123456",
      title: { text: "hello there" },
      ...toChartDataSource({
        dataSets: [{ dataRange: "Sheet1!B1:B4", yAxisId: "y1" }],
        labelRange: "Sheet1!A1:A4",
        dataSetsHaveTitle: true,
      }),
      legendPosition: "bottom",
      aggregated: true,
      stacked: true,
      labelsAsText: true,
      cumulative: true,
      axesDesign: {},
      fillArea: true,
      showValues: false,
      hideDataMarkers: false,
      zoomable: true,
      humanize: false,
      annotationLink: "https://www.odoo.com",
      annotationText: "This is an annotation text",
    });
  });

  test("Stacked line chart", () => {
    const model = new Model({
      sheets: [
        {
          name: "Sheet1",
          colNumber: 10,
          rowNumber: 10,
          rows: {},
          cells: {
            B1: "first column dataset",
            B2: "10",
            B3: "11",
            B4: "12",
          },
        },
      ],
    });
    createChart(
      model,
      { type: "line", ...toChartDataSource({ dataSets: [{ dataRange: "Sheet1!B1:B4" }] }) },
      "chartId"
    );
    expect(isChartAxisStacked(model, "chartId", "x")).toBeFalsy();
    expect(isChartAxisStacked(model, "chartId", "y")).toBeFalsy();

    updateChart(model, "chartId", { stacked: true });
    const runtime = model.getters.getChartRuntime("chartId") as any;
    expect(isChartAxisStacked(model, "chartId", "x")).toBeUndefined();
    expect(isChartAxisStacked(model, "chartId", "y")).toBe(true);
    expect(runtime.chartJsConfig.data.datasets[0].fill).toBeFalsy();
  });

  test("Area chart", () => {
    const model = new Model({
      sheets: [
        {
          name: "Sheet1",
          colNumber: 10,
          rowNumber: 10,
          rows: {},
          cells: {
            B1: "first column dataset",
            B2: "10",
            B3: "11",
            B4: "12",
            C1: "second column dataset",
            C2: "13",
            C3: "14",
            C4: "15",
          },
        },
      ],
    });
    createChart(
      model,
      {
        type: "line",
        ...toChartDataSource({ dataSets: [{ dataRange: "B1:B4" }, { dataRange: "C1:C4" }] }),
      },
      "chartId"
    );
    let runtime = model.getters.getChartRuntime("chartId") as any;
    expect(runtime.chartJsConfig.data.datasets[0].fill).toBeFalsy();

    updateChart(model, "chartId", { fillArea: true });
    runtime = model.getters.getChartRuntime("chartId") as any;
    expect(runtime.chartJsConfig.data.datasets[0].fill).toBe("origin");
    expect(runtime.chartJsConfig.data.datasets[0].backgroundColor).toBe("#4EA7F266");
    expect(runtime.chartJsConfig.data.datasets[1].fill).toBe("origin");
    expect(runtime.chartJsConfig.data.datasets[1].backgroundColor).toBe("#EA617566");
    expect(isChartAxisStacked(model, "chartId", "x")).toBeFalsy();
    expect(isChartAxisStacked(model, "chartId", "y")).toBeFalsy();
  });

  test("Stacked area chart", () => {
    const model = new Model({
      sheets: [
        {
          name: "Sheet1",
          colNumber: 10,
          rowNumber: 10,
          rows: {},
          cells: {
            B1: "first column dataset",
            B2: "10",
            B3: "11",
            B4: "12",
            C1: "second column dataset",
            C2: "13",
            C3: "14",
            C4: "15",
          },
        },
      ],
    });
    createChart(
      model,
      {
        type: "line",
        ...toChartDataSource({ dataSets: [{ dataRange: "B1:B4" }, { dataRange: "C1:C4" }] }),
      },
      "chartId"
    );
    let runtime = model.getters.getChartRuntime("chartId") as any;
    expect(runtime.chartJsConfig.data.datasets[0].fill).toBeFalsy();

    updateChart(model, "chartId", { fillArea: true, stacked: true });
    runtime = model.getters.getChartRuntime("chartId") as any;
    expect(runtime.chartJsConfig.data.datasets[0].fill).toBe("origin");
    expect(runtime.chartJsConfig.data.datasets[0].backgroundColor).toBe("#4EA7F266");
    expect(runtime.chartJsConfig.data.datasets[1].fill).toBe("-1"); // fill until the previous dataset
    expect(runtime.chartJsConfig.data.datasets[1].backgroundColor).toBe("#EA617566");
    expect(isChartAxisStacked(model, "chartId", "x")).toBeUndefined();
    expect(isChartAxisStacked(model, "chartId", "y")).toBe(true);
  });

  test("Area charts treat non-numeric values as zero", () => {
    // prettier-ignore
    const model = createModelFromGrid({
      A1: "A", B1: "1", C1: "4",
      A2: "B",          C2: "invalid",
    });
    createChart(
      model,
      {
        type: "line",
        fillArea: true,
        stacked: false,
        ...toChartDataSource({
          labelRange: "A1:A2",
          dataSets: [{ dataRange: "B1:B2" }, { dataRange: "C1:C2" }],
          dataSetsHaveTitle: false,
        }),
      },
      "chartId"
    );
    let datasets = getChartConfiguration(model, "chartId").data.datasets!;
    expect(datasets[0].data).toEqual([1, 0]);
    expect(datasets[1].data).toEqual([4, 0]);

    updateChart(model, "chartId", { stacked: true });
    datasets = getChartConfiguration(model, "chartId").data.datasets!;
    expect(datasets[0].data).toEqual([1, 0]);
    expect(datasets[1].data).toEqual([4, 0]);

    updateChart(model, "chartId", { fillArea: false });
    datasets = getChartConfiguration(model, "chartId").data.datasets!;
    expect(datasets[0].data).toEqual([1, NaN]);
    expect(datasets[1].data).toEqual([4, NaN]);
  });

  test("Trend lines have no fill color in area chart", () => {
    const model = new Model();
    setCellContent(model, "A1", "data");
    setCellContent(model, "A2", "3");
    setCellContent(model, "A3", "4");
    createChart(
      model,
      {
        type: "line",
        ...toChartDataSource({
          dataSets: [
            { dataRange: "A1:A3", trend: { type: "polynomial", order: 1, display: true } },
          ],
          dataSetsHaveTitle: false,
        }),
        fillArea: true,
      },
      "chartId"
    );
    const runtime = model.getters.getChartRuntime("chartId") as any;
    expect(runtime.chartJsConfig.data.datasets[0].fill).toBe("origin");
    expect(runtime.chartJsConfig.data.datasets[1].fill).toBe(false);
  });

  test("Line chart legend", () => {
    const model = createModelFromGrid({
      A1: "1",
      A2: "2",
      A3: "3",
      A4: "4",
    });
    createChart(
      model,
      {
        ...toChartDataSource({
          dataSets: [
            { dataRange: "Sheet1!A1:A2", backgroundColor: "#f00", label: "serie_1" },
            { dataRange: "Sheet1!A3:A4", backgroundColor: "#00f", label: "serie_2" },
          ],
          labelRange: "Sheet1!A2:A4",
        }),
        type: "line",
      },
      "1"
    );
    expect(getChartLegendLabels(model, "1")).toEqual([
      {
        fontColor: "#000000",
        fillStyle: "#f00",
        text: "serie_1",
        hidden: false,
        lineWidth: 3,
        pointStyle: "line",
        strokeStyle: "#f00",
        datasetIndex: 0,
      },
      {
        fontColor: "#000000",
        fillStyle: "#00f",
        text: "serie_2",
        hidden: false,
        lineWidth: 3,
        pointStyle: "line",
        strokeStyle: "#00f",
        datasetIndex: 1,
      },
    ]);
  });

  test("line chart runtime reflects axis bounds, grids and scale type", () => {
    const model = createModelFromGrid({
      A1: "Month",
      A2: "Jan",
      B1: "Series A",
      B2: "5",
    });

    createChart(
      model,
      {
        type: "line",
        ...toChartDataSource({
          labelRange: "A2",
          dataSets: [{ dataRange: "B2" }],
        }),
      },
      "1"
    );

    updateChart(model, "1", {
      axesDesign: {
        x: { min: 0, max: 2, gridLines: "both" },
        y: { min: 5, max: 25, gridLines: "minor" },
      },
    });

    const scales = getChartConfiguration(model, "1").options?.scales;
    expect(scales.x?.min).toBe(0);
    expect(scales.x?.max).toBe(2);
    expect(scales.x?.grid?.display).toBe(true);
    expect(scales.x?.grid?.minor?.display).toBe(true);
    expect(scales.y?.min).toBe(5);
    expect(scales.y?.max).toBe(25);
    expect(scales.y?.grid?.display).toBe(false);
    expect(scales.y?.grid?.minor?.display).toBe(true);
  });
});
