import { Model, TableStyle, UID } from "../../src";
import { TABLE_PRESETS } from "../../src/helpers/table_presets";
import { toChartDataSource } from "../test_helpers/chart_helpers";
import {
  addCfRule,
  addEqualCf,
  clearFormatting,
  colorSheetTab,
  createCarousel,
  createChart,
  createGaugeChart,
  createScorecardChart,
  createTable,
  deleteFigure,
  redo,
  setFormatting,
  setSheetBackground,
  undo,
  updateCarousel,
  updateChart,
} from "../test_helpers/commands_helpers";
import { createColorScale } from "../test_helpers/helpers";

describe("custom colors are correctly handled when formatting cells", () => {
  let model: Model;

  beforeEach(() => {
    model = new Model();
  });

  test("Adding style to cell add custom colors in the plugin", () => {
    expect(model.getters.getCustomColors()).toEqual([]);
    setFormatting(model, "A1", { fillColor: "#505050" });
    expect(model.getters.getCustomColors()).toEqual(["#505050"]);
    setFormatting(model, "B1", { textColor: "#101010" });
    expect(model.getters.getCustomColors()).toEqual(["#505050", "#101010"]);
  });

  test("Classical colors are not taken into account by the plugin", () => {
    setFormatting(model, "A1", { fillColor: "#FFFFFF", textColor: "#FF0000" });
    expect(model.getters.getCustomColors()).toEqual([]);
  });

  test("Removing style to cell keep custom colors in the plugin", () => {
    setFormatting(model, "A1", { fillColor: "#123456", textColor: "#2468BD" });
    expect(model.getters.getCustomColors()).toEqual(["#2468BD", "#123456"]);
    clearFormatting(model, "A1");
    expect(model.getters.getCustomColors()).toEqual(["#2468BD", "#123456"]);
  });

  test("Adding conditional formatting add custom colors in the plugin", () => {
    addEqualCf(model, "A1:A3,C1:D3,F1:F3", { fillColor: "#123456", textColor: "#2468BD" }, "1");
    expect(model.getters.getCustomColors()).toEqual(["#2468BD", "#123456"]);
    const rule = createColorScale(
      "2",
      { type: "value", color: 0xf500ff, value: "" },
      { type: "value", color: 0x123456, value: "" }
    ).rule;
    addCfRule(model, "B1:B5", rule);
    expect(model.getters.getCustomColors()).toEqual(["#2468BD", "#F500FF", "#123456"]);
  });

  test("Non-HEX6 lowercase colors are correctly converted", () => {
    expect(model.getters.getCustomColors()).toEqual([]);
    setFormatting(model, "A1", { fillColor: "#123", textColor: "#F0F000" });
    expect(model.getters.getCustomColors()).toEqual(["#F0F000", "#112233"]);
  });

  test("duplicated colors on cells only appears once", () => {
    setFormatting(model, "A1", { fillColor: "#123456", textColor: "#123456" });
    expect(model.getters.getCustomColors()).toEqual(["#123456"]);
  });

  test("Custom colors with undo/redo", () => {
    setFormatting(model, "A1", { fillColor: "#123456" });
    setFormatting(model, "A2", { fillColor: "#FF0058" });
    expect(model.getters.getCustomColors()).toEqual(["#123456", "#FF0058"]);
    undo(model);
    expect(model.getters.getCustomColors()).toEqual(["#123456"]);
    redo(model);
    expect(model.getters.getCustomColors()).toEqual(["#123456", "#FF0058"]);
  });
});

describe("custom colors are correctly handled when editing charts", () => {
  let model: Model;
  let sheetId: UID;

  beforeEach(() => {
    model = new Model();
    sheetId = model.getters.getActiveSheetId();
  });
  test("Chart background colors are taken into account", () => {
    expect(model.getters.getCustomColors()).toEqual([]);
    createChart(
      model,
      {
        type: "bar",
        ...toChartDataSource({
          dataSets: [{ dataRange: "A1:A10" }],
          labelRange: "A1",
        }),
        background: "#123456",
      },
      "1",
      sheetId
    );
    expect(model.getters.getCustomColors()).toEqual(["#123456"]);
    updateChart(model, "1", {
      title: { text: "a title" },
      ...toChartDataSource({
        dataSets: [],
        labelRange: "A1",
        dataSetsHaveTitle: false,
      }),
      type: "bar",
      stacked: false,
      legendPosition: "none",
      background: "#112233",
      aggregated: false,
    });
    expect(model.getters.getCustomColors()).toEqual(["#112233", "#123456"]);
    deleteFigure(model, "1", sheetId);
    expect(model.getters.getCustomColors()).toEqual(["#112233", "#123456"]);
  });

  test("Gauge colors are taken into account", () => {
    expect(model.getters.getCustomColors()).toEqual([]);
    createGaugeChart(model, {
      title: { text: "a title" },
      type: "gauge",
      dataRange: "B1:B4",
      sectionRule: {
        rangeMin: "0",
        rangeMax: "100",
        colors: {
          lowerColor: "#112233",
          middleColor: "#123456",
          upperColor: "#2468BD",
        },
        lowerInflectionPoint: {
          type: "number" as const,
          value: "33",
          operator: "<=" as const,
        },
        upperInflectionPoint: {
          type: "number" as const,
          value: "66",
          operator: "<=" as const,
        },
      },
    });
    expect(model.getters.getCustomColors()).toEqual(["#2468BD", "#112233", "#123456"]);
  });

  test("Scorecard colors are taken into account", () => {
    expect(model.getters.getCustomColors()).toEqual([]);
    createScorecardChart(
      model,
      {
        baselineColorDown: "#112233",
        baselineColorUp: "#123456",
      },
      "1"
    );
    expect(model.getters.getCustomColors()).toEqual(["#112233", "#123456"]);
  });

  test("Sheet colors are taken into account", () => {
    colorSheetTab(model, model.getters.getActiveSheetId(), "#FFFF16");
    setSheetBackground(model, "#FF16FF");

    expect(model.getters.getCustomColors()).toEqual(["#FFFF16", "#FF16FF"]);
  });

  test("Chart data series colors are taken into account", () => {
    expect(model.getters.getCustomColors()).toEqual([]);
    createChart(
      model,
      {
        type: "bar",
        ...toChartDataSource({
          dataSets: [
            {
              dataRange: "A1:A10",
              backgroundColor: "#112233",
              trend: { type: "polynomial", order: 2, color: "#123456" },
            },
          ],
        }),
      },
      "1"
    );
    expect(model.getters.getCustomColors()).toEqual(["#112233", "#123456"]);
  });

  test("duplicated colors on cell and chart only appears once", () => {
    setFormatting(model, "A1", { fillColor: "#123456" });
    createChart(
      model,
      {
        type: "bar",
        ...toChartDataSource({
          dataSets: [{ dataRange: "A1:A10" }],
          labelRange: "A1",
        }),
        background: "#123456",
      },
      "1",
      sheetId
    );
    expect(model.getters.getCustomColors()).toEqual(["#123456"]);
  });

  test("custom colors from model imported data", () => {
    setFormatting(model, "A1", { fillColor: "#123456" });
    createChart(model, { type: "bar", background: "#654987" }, "1", sheetId);
    const importedModel = new Model(model.exportData());
    expect(importedModel.getters.getCustomColors()).toEqual(["#654987", "#123456"]);
  });

  test("Carousel title color are taken into account", () => {
    expect(model.getters.getCustomColors()).toEqual([]);
    createCarousel(model, { title: { text: "Hello", color: "#123456" }, items: [] }, "id");
    expect(model.getters.getCustomColors()).toEqual(["#123456"]);

    updateCarousel(model, "id", { title: { text: "Hello", color: "#654321" }, items: [] });
    expect(model.getters.getCustomColors()).toEqual(["#654321", "#123456"]);

    const model2 = new Model(model.exportData());
    expect(model2.getters.getCustomColors()).toEqual(["#654321"]);
  });
});

test("custom colors from config", () => {
  const data = {};
  const model = new Model(data, { customColors: ["#875A7B", "not a valid color"] });
  expect(model.getters.getCustomColors()).toEqual(["#875A7B"]);
});

describe("Custom colors with table styles", () => {
  let model: Model;
  const customStyle: TableStyle = {
    wholeTable: { border: { bottom: { color: "#123456", style: "thin" } } },
    firstColumn: { style: { fillColor: "#234567" } },
    totalRow: { style: { textColor: "#345678" } },
    category: "dark",
    displayName: "customStyle",
    templateName: "dark",
    primaryColor: "#123456",
  };

  beforeEach(() => {
    TABLE_PRESETS["customStyle"] = customStyle;
    model = new Model();
  });

  afterEach(() => {
    delete TABLE_PRESETS["customStyle"];
  });

  test("Custom colors are added from table styles", () => {
    createTable(model, "A1:B2", { styleId: "customStyle", totalRow: true, firstColumn: true });
    expect(model.getters.getCustomColors()).toEqual(["#345678", "#234567", "#123456"]);
  });

  test("Table elements that are not displayed are not added to custom colors", () => {
    createTable(model, "A1:B2", { styleId: "customStyle", totalRow: false, firstColumn: false });
    expect(model.getters.getCustomColors()).toEqual(["#123456"]);
  });
});
