import React, { useState, useRef, Fragment } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
  AgCartesianChartOptions,
  AgChartsInstance,
} from "ag-charts-enterprise";
import "ag-charts-enterprise";
import clone from "clone";

const quarters = Array.from({ length: 14 }, (_, id) => ({
  id,
  label: `week ${id}`,
  toString: () => `week ${id}`,
}));
const data = [
  { quarter: quarters[3], week: 3, iphone: 60, android: 50 },
  { quarter: quarters[4], week: 4, iphone: 185, android: 90 },
  { quarter: quarters[5], week: 5, iphone: 148, android: 70 },
  { quarter: quarters[6], week: 6, iphone: 130, android: 130 },
  { quarter: quarters[9], week: 9, iphone: 62, android: 120 },
  { quarter: quarters[10], week: 10, iphone: 137, android: 105 },
  { quarter: quarters[11], week: 11, iphone: 121, android: 100 },
];
function insertAfter(
  data: {
    week: number;
  }[],
  afterWeek: number,
  toInsert: any,
) {
  const insertIndex = data.findIndex(({ week }) => week > afterWeek);
  if (insertIndex === -1) {
    return data.concat([toInsert]);
  }
  const newData = data.slice();
  newData.splice(insertIndex, 0, toInsert);
  return newData;
}

const ChartExample = () => {
  const chartRef = useRef<AgChartsInstance>(null);
  const [options, setOptions] = useState<AgCartesianChartOptions>({
    animation: {
      enabled: true,
    },
    data: data,
    series: [
      {
        type: "line",
        xKey: "quarter",
        yKey: "iphone",
        label: {
          formatter: ({ value }) => String(value),
        },
        // visible: false
      },
      {
        type: "line",
        xKey: "quarter",
        yKey: "android",
        label: {
          formatter: ({ value }) => String(value),
        },
        // visible: false
      },
    ],
    axes: [
      {
        position: "left",
        type: "number",
      },
      {
        position: "bottom",
        type: "category",
      },
    ],
  });

  const actionReset = () => {
    const nextOptions = clone(options);

    nextOptions.data = data;

    setOptions(nextOptions);
  };

  const actionAddEndWeek = () => {
    const nextOptions = clone(options);

    const data = nextOptions.data ?? [];
    const nextWeek = data.slice(-1)[0].week + 1;
    nextOptions.data = [
      ...data,
      {
        quarter: quarters[nextWeek],
        week: nextWeek,
        iphone: 78 * (Math.random() - 0.5),
        android: 65 * (Math.random() - 0.5),
      },
    ];

    setOptions(nextOptions);
  };

  const actionAddStartWeek = () => {
    const nextOptions = clone(options);

    const data = nextOptions.data ?? [];
    const prevWeek = data[0].week - 1;
    nextOptions.data = [
      {
        quarter: quarters[prevWeek],
        week: prevWeek,
        iphone: 78 * (Math.random() - 0.5),
        android: 65 * (Math.random() - 0.5),
      },
      ...data,
    ];

    setOptions(nextOptions);
  };

  const actionAddWeek12and13 = () => {
    const nextOptions = clone(options);

    nextOptions.data = insertAfter(nextOptions.data!, 11, {
      quarter: quarters[12],
      week: 12,
      iphone: 78,
      android: 67,
    });
    nextOptions.data = insertAfter(nextOptions.data, 12, {
      quarter: quarters[13],
      week: 13,
      iphone: 138,
      android: 120,
    });
    nextOptions.data = nextOptions.data;

    setOptions(nextOptions);
  };

  const actionAddWeek7and8 = () => {
    const nextOptions = clone(options);

    nextOptions.data = insertAfter(nextOptions.data!, 6, {
      quarter: quarters[7],
      week: 7,
      iphone: 142,
      android: 67,
    });
    nextOptions.data = insertAfter(nextOptions.data, 7, {
      quarter: quarters[8],
      week: 8,
      iphone: 87,
      android: 120,
    });
    nextOptions.data = nextOptions.data;

    setOptions(nextOptions);
  };

  const reverse = () => {
    const nextOptions = clone(options);

    nextOptions.data = nextOptions.data!.slice().reverse();

    setOptions(nextOptions);
  };

  const reorder = () => {
    const nextOptions = clone(options);

    nextOptions.data = [...(nextOptions.data ?? [])];
    nextOptions.data?.forEach((d) => (d.random = Math.random()));
    nextOptions.data?.sort((a, b) => a.random - b.random);

    setOptions(nextOptions);
  };

  const rapidUpdate = () => {
    chartRef.current!.updateDelta({
      data: [...data, { quarter: quarters[12], iphone: 78, android: 67 }],
    });
    chartRef.current!.waitForUpdate().then(() => {
      chartRef.current!.updateDelta({
        data: [
          ...data,
          { quarter: quarters[12], week: 12, iphone: 78, android: 67 },
          { quarter: quarters[13], week: 13, iphone: 138, android: 120 },
        ],
      });
    });
  };

  return (
    <Fragment>
      <div className="toolbar">
        <button onClick={actionReset}>Reset</button>
        <hr />
        <button onClick={actionAddStartWeek}>Add Start Week</button>
        <button onClick={actionAddEndWeek}>Add End Week</button>
        <button onClick={actionAddWeek12and13}>Add Weeks 12+13</button>
        <button onClick={actionAddWeek7and8}>Add Weeks 7+8</button>
        <hr />
        <button onClick={reverse}>Reverse</button>
        <button onClick={reorder}>Reorder</button>
        <button onClick={rapidUpdate}>Rapid Update</button>
      </div>
      <AgCharts ref={chartRef} options={options as any} />
    </Fragment>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);

/** DARK MODE START **/
import { AgCharts as __chartAPI } from "ag-charts-community";

let darkmode =
  (localStorage["documentation:darkmode"] ||
    String(matchMedia("(prefers-color-scheme: dark)").matches)) === "true";

const isAgThemeOrUndefined = (theme) => {
  return (
    theme == null || (typeof theme === "string" && theme.startsWith("ag-"))
  );
};

const getDarkmodeTheme = (theme = "ag-default", preset) => {
  const baseTheme =
    preset === "price-volume" ? "ag-financial" : theme.replace(/-dark$/, "");
  return darkmode ? baseTheme + "-dark" : baseTheme;
};

__chartAPI.optionsMutationFn = function update(options, preset) {
  const nextOptions = { ...options };
  const theme = options.theme;
  if (isAgThemeOrUndefined(theme)) {
    nextOptions.theme = getDarkmodeTheme(theme, preset);
  } else if (
    typeof theme === "object" &&
    isAgThemeOrUndefined(theme.baseTheme)
  ) {
    nextOptions.theme = {
      ...options.theme,
      baseTheme: getDarkmodeTheme(theme.baseTheme, preset),
    };
  }
  return nextOptions;
};

const applyDarkmode = () => {
  document.documentElement.setAttribute("data-dark-mode", darkmode);
  const charts = document.querySelectorAll("[data-ag-charts]");
  charts.forEach((element) => {
    const chart = __chartAPI.getInstance(element.parentElement);
    if (chart == null) return;
    // This is just needed to trigger the theme update
    chart.update(chart.getOptions());
  });
  return charts.length !== 0;
};

if (!applyDarkmode()) {
  /* React defers updates. Rather than try and hook into the API, just wait until the darkmode is applied. */
  const observer = new MutationObserver(() => {
    if (applyDarkmode()) {
      observer.disconnect();
    }
  });
  observer.observe(document.body, {
    attributes: true,
    childList: true,
    subtree: true,
  });
}
window.addEventListener("message", (event) => {
  if (event.data && event.data.type === "color-scheme-change") {
    darkmode = event.data.darkmode;
    applyDarkmode();
  }
});
/** DARK MODE END **/
