import React from "react";
import classNames from "classnames";
import {
  PingInfo,
  PingRollupInfo,
  PingStatus,
  useSolanaPingInfo,
} from "providers/stats/SolanaPingProvider";
import { Bar } from "react-chartjs-2";
import { ChartOptions, ChartTooltipModel } from "chart.js";
import { Cluster, useCluster } from "providers/cluster";

export function SolanaPingCard() {
  const { cluster } = useCluster();

  if (cluster === Cluster.Custom) {
    return null;
  }

  return (
    <div className="card">
      <div className="card-header">
        <h4 className="card-header-title">Solana Ping Stats</h4>
      </div>
      <PingBarBody />
    </div>
  );
}

function PingBarBody() {
  const pingInfo = useSolanaPingInfo();

  if (pingInfo.status !== PingStatus.Ready) {
    return (
      <StatsNotReady
        error={pingInfo.status === PingStatus.Error}
        retry={pingInfo.retry}
      />
    );
  }

  return <PingBarChart pingInfo={pingInfo} />;
}

type StatsNotReadyProps = { error: boolean; retry?: Function };
function StatsNotReady({ error, retry }: StatsNotReadyProps) {
  if (error) {
    return (
      <div className="card-body text-center">
        There was a problem loading solana ping stats.{" "}
        {retry && (
          <button
            className="btn btn-white btn-sm"
            onClick={() => {
              retry();
            }}
          >
            <span className="fe fe-refresh-cw me-2"></span>
            Try Again
          </button>
        )}
      </div>
    );
  }

  return (
    <div className="card-body text-center">
      <span className="spinner-grow spinner-grow-sm me-2"></span>
      Loading
    </div>
  );
}

type Series = "short" | "medium" | "long";
const SERIES: Series[] = ["short", "medium", "long"];
const SERIES_INFO = {
  short: {
    label: (index: number) => index,
    interval: "30m",
  },
  medium: {
    label: (index: number) => index * 4,
    interval: "2h",
  },
  long: {
    label: (index: number) => index * 12,
    interval: "6h",
  },
};

const CUSTOM_TOOLTIP = function (this: any, tooltipModel: ChartTooltipModel) {
  // Tooltip Element
  let tooltipEl = document.getElementById("chartjs-tooltip");

  // Create element on first render
  if (!tooltipEl) {
    tooltipEl = document.createElement("div");
    tooltipEl.id = "chartjs-tooltip";
    tooltipEl.innerHTML = `<div class="content"></div>`;
    document.body.appendChild(tooltipEl);
  }

  // Hide if no tooltip
  if (tooltipModel.opacity === 0) {
    tooltipEl.style.opacity = "0";
    return;
  }

  // Set Text
  if (tooltipModel.body) {
    const { label } = tooltipModel.dataPoints[0];
    const tooltipContent = tooltipEl.querySelector("div");
    if (tooltipContent) {
      tooltipContent.innerHTML = `${label}`;
    }
  }

  // Enable tooltip and set position
  const canvas: Element = this._chart.canvas;
  const position = canvas.getBoundingClientRect();
  tooltipEl.style.opacity = "1";
  tooltipEl.style.left =
    position.left + window.pageXOffset + tooltipModel.caretX + "px";
  tooltipEl.style.top =
    position.top + window.pageYOffset + tooltipModel.caretY + "px";
};

const CHART_OPTION: ChartOptions = {
  tooltips: {
    intersect: false, // Show tooltip when cursor in between bars
    enabled: false, // Hide default tooltip
    custom: CUSTOM_TOOLTIP,
  },
  legend: {
    display: false,
  },
  scales: {
    xAxes: [
      {
        ticks: {
          display: false,
        },
        gridLines: {
          display: false,
        },
      },
    ],
    yAxes: [
      {
        ticks: {
          stepSize: 100,
          fontSize: 10,
          fontColor: "#EEE",
          beginAtZero: true,
          display: true,
        },
        gridLines: {
          display: false,
        },
      },
    ],
  },
  animation: {
    duration: 0, // general animation time
  },
  hover: {
    animationDuration: 0, // duration of animations when hovering an item
  },
  responsiveAnimationDuration: 0, // animation duration after a resize
};

function PingBarChart({ pingInfo }: { pingInfo: PingRollupInfo }) {
  const [series, setSeries] = React.useState<Series>("short");
  const seriesData = pingInfo[series] || [];
  const maxMean = seriesData.reduce((a, b) => {
    return Math.max(a, b.mean);
  }, 0);
  const seriesLength = seriesData.length;
  const backgroundColor = (val: PingInfo) => {
    if (val.submitted === 0) {
      return "#08a274";
    }
    return val.loss > 0.5 ? "#f00" : "#00D192";
  };
  const chartData: Chart.ChartData = {
    labels: seriesData.map((val, i) => {
      if (val.submitted === 0) {
        return `
        <div class="label">
          <p class="mb-0">Ping statistics unavailable</p>
          ${SERIES_INFO[series].label(seriesLength - i)}min ago
        </div>
        `;
      }

      return `
        <div class="value">${val.mean} ms</div>
        <div class="label">
          <p class="mb-0">${val.confirmed} of ${val.submitted} confirmed</p>
        ${
          val.loss
            ? `<p class="mb-0">${val.loss.toLocaleString(undefined, {
                style: "percent",
                minimumFractionDigits: 2,
              })} loss</p>`
            : ""
        }
        ${SERIES_INFO[series].label(seriesLength - i)}min ago
        </div>
      `;
    }),
    datasets: [
      {
        minBarLength: 2,
        backgroundColor: seriesData.map(backgroundColor),
        hoverBackgroundColor: seriesData.map(backgroundColor),
        borderWidth: 0,
        data: seriesData.map((val) => {
          if (val.submitted === 0) {
            return maxMean * 0.5;
          }

          return val.mean || 0;
        }),
      },
    ],
  };

  return (
    <div className="card-body py-3">
      <div className="align-box-row align-items-start justify-content-between">
        <div className="d-flex justify-content-between w-100">
          <span className="mb-0 font-size-sm">Average Ping Time</span>

          <div className="font-size-sm">
            {SERIES.map((key) => (
              <button
                key={key}
                onClick={() => setSeries(key)}
                className={classNames("btn btn-sm btn-white ms-2", {
                  active: series === key,
                })}
              >
                {SERIES_INFO[key].interval}
              </button>
            ))}
          </div>
        </div>

        <div
          id="perf-history"
          className="mt-3 d-flex justify-content-end flex-row w-100"
        >
          <div className="w-100">
            <Bar data={chartData} options={CHART_OPTION} height={80} />
          </div>
        </div>
      </div>
    </div>
  );
}
