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

const data = [
  { label: "Android", value: 56.9 },
  { label: "iOS", value: 22.5 },
  { label: "BlackBerry", value: 6.8 },
  { label: "Symbian", value: 8.5 },
  { label: "Bada", value: 2.6 },
  { label: "Windows", value: 1.9 },
];
const moreLabels = ["SteamOS", "ChromeOS", "Palm OS"];
const filter = (...labels: string[]) => {
  return (d: (typeof data)[number]) => labels.includes(d.label);
};
function randomIndex(array: unknown[]) {
  const index = Math.floor(Math.random() * array.length);
  return index;
}
function addData(
  position: "start" | "mid" | "end" | number = "end",
  inData: any[],
) {
  const nextLabel = [...data.map(({ label }) => label), ...moreLabels].find(
    (l) => !inData?.some((d) => d.label === l),
  );
  if (!nextLabel) return inData;
  const newDatum = { label: nextLabel, value: Math.random() * 5 + 0.5 };
  const newData = [...(inData ?? [])];
  let newPosition = 0;
  if (typeof position === "number") newPosition = position;
  if (position === "start") newPosition = 0;
  if (position === "mid") newPosition = Math.floor(newData.length / 2);
  if (position === "end") newPosition = newData.length;
  newData.splice(newPosition, 0, newDatum);
  return newData;
}
function removeData(
  position: "start" | "mid" | "end" | number = "end",
  inData: any[],
) {
  const newData = [...(inData ?? [])];
  let index = 0;
  if (typeof position === "number") index = position;
  if (position === "start") index = 0;
  if (position === "mid") index = Math.floor(newData.length / 2);
  if (position === "end") index = -1;
  newData.splice(index, 1);
  return newData;
}

const ChartExample = () => {
  const [options, setOptions] = useState<AgPolarChartOptions>({
    animation: {
      enabled: true,
    },
    data: [...data],
    series: [
      {
        type: "pie",
        angleKey: "value",
        calloutLabelKey: "label",
        sectorLabelKey: "value",
        sectorLabel: {
          color: "white",
          fontWeight: "bold",
          formatter: ({ datum }) =>
            datum["value"]
              ? `${Math.round(parseFloat(datum["value"]) * 100) / 100}`
              : "",
        },
      },
    ],
  });

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

    nextOptions.data = [...data];
    chart.update(options as any);

    setOptions(nextOptions);
  };

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

    nextOptions.data = [
      ...(nextOptions.data ?? []).map((d: any) => ({
        ...d,
        originalValue: d.originalValue ?? d.value,
        value: (d.originalValue ?? d.value) * (Math.random() * 5 + 0.5),
      })),
    ];

    setOptions(nextOptions);
  };

  const add = (position: "start" | "mid" | "end" = "end") => {
    const nextOptions = clone(options);

    nextOptions.data = addData(position, nextOptions.data!);

    setOptions(nextOptions);
  };

  const remove = (position: "start" | "mid" | "end" = "end") => {
    const nextOptions = clone(options);

    nextOptions.data = removeData(position, nextOptions.data!);

    setOptions(nextOptions);
  };

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

    const index = Math.floor(nextOptions.data!.length / 2);
    nextOptions.data = removeData(index, addData(index + 1, nextOptions.data!));

    setOptions(nextOptions);
  };

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

    const newData = [...(nextOptions.data ?? [])];
    newData.sort(() => Math.random() - 0.5);
    nextOptions.data = newData;

    setOptions(nextOptions);
  };

  const rapidUpdates = () => {
    reset();
    setTimeout(() => randomise(), 300);
    setTimeout(() => randomise(), 600);
    setTimeout(() => randomise(), 900);
  };

  return (
    <Fragment>
      <div className="toolbar">
        <button onClick={reset}>Reset</button>
        <button onClick={randomise}>Randomise</button>
        <button onClick={() => add("start")}>Add (Start)</button>
        <button onClick={() => remove("start")}>Remove (Start)</button>
        <button onClick={() => add("mid")}>Add (Middle)</button>
        <button onClick={() => remove("mid")}>Remove (Middle)</button>
        <button onClick={() => add("end")}>Add (End)</button>
        <button onClick={() => remove("end")}>Remove (End)</button>
        <button onClick={() => change("mid")}>Change (Middle)</button>
        <button onClick={shuffle}>Shuffle</button>
        <button onClick={rapidUpdates}>Rapid Updates</button>
      </div>
      <AgCharts 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 **/
