import React, { useEffect, useRef, useMemo, useState } from "react";
import Highcharts from "highcharts";
import HighchartsReact from "highcharts-react-official";
import HighchartsMore from "highcharts/highcharts-more";
import Highcharts3D from "highcharts/highcharts-3d";
import HighchartsHeatmap from "highcharts/modules/heatmap";
import HighchartsStock from "highcharts/modules/stock";
import HighchartsVenn from "highcharts/modules/venn";
import HighchartsTreemap from "highcharts/modules/treemap";
import HighchartsExporting from 'highcharts/modules/exporting';
import HighchartsExportData from 'highcharts/modules/export-data';
import HighchartsOfflineExporting from "highcharts/modules/offline-exporting";

import "./Chart.style.scss";
import { Button } from "../Button";
import { Menu } from "../Menu";
import { Tooltip } from "../Tooltip";
import TableChartOutlinedIcon from "@mui/icons-material/TableChartOutlined";
import FileDownloadOutlinedIcon from "@mui/icons-material/FileDownloadOutlined";
import { ReactComponent as ExpandIcon } from "../../assets/expand-icon.svg";
import { ReactComponent as Collapse } from "../../assets/collapse-new.svg";
import { ReactComponent as ChartDropdown } from "../../assets/Chart-dropdown.svg";
import { ReactComponent as EmptyStateImage } from "../../assets/emptyStateImage.svg";

// Rounded bars
const borderRadius = require("highcharts-border-radius");

// Load Highcharts modules
if (typeof Highcharts === "object") {
  [
    HighchartsMore,
    Highcharts3D,
    HighchartsHeatmap,
    HighchartsStock,
    HighchartsVenn,
    HighchartsTreemap,
    borderRadius,
    HighchartsExporting,
    HighchartsExportData,
    HighchartsOfflineExporting,
  ].forEach((mod) => {
    if (typeof mod === "function") mod(Highcharts);
  });
}

export const Chart = ({
  graphType = "column",
  xAxisCategories,
  xAxisTitle = "X Axis",
  yAxisTitle = "Y Axis",
  seriesData,
  graphTitle,
  stackedColumn = false,
  is3D = false,
  showSubTitle = false,
  onChartDownload = () => {},
  fallbackContent = null,
  topRightOptions = null,
  showSwitchButton = false,
  showChartTypeDropdown = false,
  showDownloadButton = true,
  chartTypesOptions = [],
  selectedChart,
  chartMenuProps,
  showScrollX = false,
  topLeftOptions = null,
  cardContainer = true,
  subtitleText = "",
  legendXPosition = null,
  legendYPosition = null,
  xAxisTitlePositionY = null,
  customTooltipFormatter = null,
  sharedTooltip = false,
  showchart = true,
  setShowChart = () => {},
  plotOptionsEvents,
  customSystemButton = null,
  handleChartExpand = () => {},
  chartMarginBottom = 150,
  showHeader = true,
  height = null,
  width = null,
  showExpandButton = true,
  showDownloadMenu = true,
  showBuiltInDownloadOptions = true,
  downloadMenuOptions = [],
  customLegend = null,
  customLegendStyle = null,
  yAxisTitleRight,
  chartOptions = {},
  titleOptions = {},
  xAxisOptions = {},
  yAxisOptions = {},
  yAxisLeftOptions = {},
  yAxisRightOptions = {},
  zAxisOptions = {},
  tooltipOptions = {},
  plotOptionsOptions = {},
  subtitleOptions = {},
  creditsOptions = {},
  legendOptions = {},
  colorAxisOptions = {},
  seriesOptions = null,
  additionalOptions = {},
  hoveredXAxisIndex = null,
  exportingOptions = {},
  aboveChartComponent = null,
  isEmpty = false,
}) => {
  const [isExpanded, setIsExpanded] = useState(false);
  const [isAnimating, setIsAnimating] = useState(false);
  const [showChartList, setShowChartList] = useState(false);
  const [selectMenuAnchor, setSelectMenuAnchor] = useState(null);
  const [showDownloadList, setShowDownloadList] = useState(false);
  const [downloadMenuAnchor, setDownloadMenuAnchor] = useState(null);
  const chartComponentRef = useRef(null);
  const containerRef = useRef(null);

  const getBuiltInDownloadOptions = () => {
    const chart = chartComponentRef.current?.chart;
    if (!chart) return [];

    const globalExporting = Highcharts.getOptions().exporting || {};
    const instanceExporting = chart.options?.exporting || {};

    const menuItemDefs = {
      ...(globalExporting.menuItemDefinitions || {}),
      ...(instanceExporting.menuItemDefinitions || {}),
    };

    const formatKey = (str) => {
      const withSpaces = str.replace(/([a-z])([A-Z])/g, "$1 $2");
      return withSpaces.charAt(0).toUpperCase() + withSpaces.slice(1);
    };

    return Object.keys(menuItemDefs)
      .filter(
        (item) =>
          typeof item === 'string' &&
          item !== 'separator' &&
          item !== 'viewFullscreen' &&
          (item.startsWith('download') || item === 'printChart')
      )
      .map((item) => ({
        label: menuItemDefs[item]?.text || formatKey(item),
        value: item,
        onClick: () => {
          if (typeof menuItemDefs[item].onclick === 'function') {
            menuItemDefs[item].onclick.call(chart);
          }
          setShowDownloadList(false);
        },
      }));
  };
  // ============================
  // FULLSCREEN ENTER/EXIT LOGIC
  // ============================

  const enterFullscreen = () => {
    const elem = containerRef.current;
    if (!elem) return;

    setIsAnimating(true);
    elem.classList.add("fullscreen-animating");

    setTimeout(() => {
      if (elem.requestFullscreen) elem.requestFullscreen();
      else if (elem.webkitRequestFullscreen) elem.webkitRequestFullscreen();
      else if (elem.msRequestFullscreen) elem.msRequestFullscreen();

      setIsExpanded(true);
      handleChartExpand(true);
      elem.classList.remove("fullscreen-animating");
    }, 200);
  };

  const exitFullscreen = () => {
    const elem = containerRef.current;
    if (!elem) return;

    setIsAnimating(true);
    elem.classList.add("fullscreen-animating-out");

    setTimeout(() => {
      if (document.exitFullscreen) document.exitFullscreen();
      else if (document.webkitExitFullscreen) document.webkitExitFullscreen();
      else if (document.msExitFullscreen) document.msExitFullscreen();

      setIsExpanded(false);
      handleChartExpand(false);
      elem.classList.remove("fullscreen-animating-out");
    }, 200);
  };

  // ESC or user-exit fullscreen handling
  useEffect(() => {
    const handleFullscreenChange = () => {
      const fs =
        document.fullscreenElement ||
        document.webkitFullscreenElement ||
        document.msFullscreenElement;

      if (!fs) {
        setIsExpanded(false);
        handleChartExpand(false);
      }
    };

    document.addEventListener("fullscreenchange", handleFullscreenChange);
    document.addEventListener("webkitfullscreenchange", handleFullscreenChange);

    return () => {
      document.removeEventListener("fullscreenchange", handleFullscreenChange);
      document.removeEventListener(
        "webkitfullscreenchange",
        handleFullscreenChange
      );
    };
  }, []);

  // Resize chart when expanded
  useEffect(() => {
    if (!chartComponentRef?.current) return;

    const chart = chartComponentRef.current.chart;

    const updateSize = () => {
      const windowHeight = window.innerHeight;
      const windowWidth = window.innerWidth;

      chart.setSize(
        windowWidth < 768 ? windowWidth - 40 : null,
        isExpanded ? windowHeight - 98 : "auto",
        false
      );
    };

    updateSize();
    window.addEventListener("resize", updateSize);

    return () => window.removeEventListener("resize", updateSize);
  }, [isExpanded]);

  useEffect(() => {
    if (!chartComponentRef?.current) return;
    const chart = chartComponentRef.current.chart;
    if (!chart) return;

    if (hoveredXAxisIndex !== null && hoveredXAxisIndex !== undefined) {
      const points = chart.series.reduce((acc, series) => {
        const point = series.points?.[hoveredXAxisIndex];
        if (point) acc.push(point);
        return acc;
      }, []);

      if (points.length > 0) {
        chart.tooltip.refresh(sharedTooltip ? points : points[0]);
        chart.xAxis[0].drawCrosshair(null, points[0]);
      }
    } else {
      chart.tooltip.hide();
      chart.xAxis[0].hideCrosshair();
    }
  }, [hoveredXAxisIndex, sharedTooltip]);

  function safeStringify(value, fallback) {
    try {
      if (!value) return fallback;
      return JSON.stringify(value);
    } catch {
      return fallback;
    }
  }

  // ============================
  // Highcharts Options Memo
  // ============================
  const graphData = useMemo(
    () => ({
      chart: {
        type: graphType,
        scrollablePlotArea: {
          minWidth: showScrollX ? xAxisCategories?.length * 80 : undefined,
          opacity: 1,
          scrollPositionX: 0,
        },
        marginBottom: chartMarginBottom,
        width: width,
        style: { fontFamily: "Manrope, sans-serif" },
        height: isExpanded ? window.innerHeight - 108 : height || "auto",
        options3d: is3D
          ? {
              enabled: true,
              alpha: 10,
              beta: 30,
              depth: 550,
              viewDistance: 10,
            }
          : undefined,
        ...(chartOptions || {}),
      },
      title: {
        text: null, // remove title
        ...(titleOptions || {}),
      },
      exporting: {
        buttons: {
          contextButton: {
            enabled: false,
          },
        },
        ...(exportingOptions || {}),
      },
      xAxis: {
        categories: xAxisCategories,
        crosshair: true,
        lineColor: "#D9DDE7",
        title: {
          text: xAxisTitle,
          align: "middle",
          reserveSpace: true,
          y: xAxisTitlePositionY
            ? xAxisTitlePositionY
            : showScrollX
            ? graphType === "scatter3d"
              ? 130
              : 40
            : 3,
        },
        labels: {
          autoRotation: [-45, -60], // Highcharts will choose best rotation automatically
          rotation: undefined,
          style: {
            whiteSpace: "nowrap",
          },
        },
        ...(xAxisOptions || {}),
      },

      yAxis: [
        {
          // Left axis
          title: {
            text: yAxisTitle,
            x: -12,
            align: "middle",
            margin: 16,
          },
          lineWidth: 1,
          lineColor: "#D9DDE7",
          gridLineDashStyle: "Dash",
          gridLineWidth: 1,
          gridLineColor: "#D9DDE7",
          labels: {},
          opposite: false,
          ...(yAxisOptions || {}),
          ...(yAxisLeftOptions || {}),
        },
        ...(yAxisTitleRight
          ? [
              {
                title: {
                  text: yAxisTitleRight,
                  x: 12,
                  align: "middle",
                  margin: 16,
                },
                lineWidth: 1,
                lineColor: "#D9DDE7",
                gridLineDashStyle: "Dash",
                gridLineWidth: 1,
                gridLineColor: "#D9DDE7",
                labels: {},
                opposite: true,
                ...(yAxisOptions || {}),
                ...(yAxisRightOptions || {}),
              },
            ]
          : []),
      ],

      zAxis: is3D
        ? {
            min: 0,
            max: 10,
            ...(zAxisOptions || {}),
          }
        : zAxisOptions && Object.keys(zAxisOptions).length
        ? zAxisOptions
        : undefined,
      tooltip: {
        useHTML: true,
        className: "custom-tooltip",
        backgroundColor: "#ffffff",
        borderRadius: 8,
        borderWidth: 0,
        borderColor: "transparent",
        outside: false,
        shared: sharedTooltip,
        shadow: {
          color: "rgba(0, 0, 0, 0.2)",
          offsetX: 2,
          offsetY: 2,
          opacity: 0.3,
        },
        style: {
          fontFamily: "'Manrope', sans-serif",
          color: "#1F2B4D",
        },
        positioner(labelWidth, labelHeight, point) {
          const chart = this.chart;
          const left = chart.plotLeft;
          const right = chart.plotLeft + chart.plotWidth;
          const top = chart.plotTop;
          const bottom = chart.plotTop + chart.plotHeight;

          let x = point.plotX + left - labelWidth / 2;
          let y = point.plotY + top - labelHeight - 10;

          if (x < left) {
            x = left + 5;
          }

          if (y < top) {
            y = top + 5;
          }

          if (x + labelWidth > right) {
            x = right - labelWidth - 5;
          }

          if (y + labelHeight > bottom) {
            y = bottom - labelHeight - 5;
          }

          return { x, y };
        },
        formatter: function () {
          if (customTooltipFormatter) {
            return customTooltipFormatter(this);
          } else if (this.point.value !== undefined) {
            return `
            <span class="tooltip-key">X: ${this.point.x} Y: ${this.point.y}</span><br/>
            <b class="tooltip-value">Value: ${this.point.value}</b>`;
          } else {
            return `
            <span style="color:${this.color};"">●</span>
            <span class="tooltip-key">${this.key}: </span>
            <b class="tooltip-value">${this.y.toLocaleString()}</b>
          `;
          }
        },
        ...(tooltipOptions || {}),
      },

      plotOptions: {
        scatter3d: {
          width: 10,
          height: 10,
          depth: 10,
          marker: { radius: 4, symbol: "circle" },
        },
        column: {
          pointPadding: 0.2,
          groupPadding: 0.1,
          borderWidth: 0,
          borderRadius: 8,
          stacking: stackedColumn ? "normal" : null,
        },
        areaspline: { fillOpacity: 0.25 },
        heatmap: { borderWidth: 1, borderColor: "#ffffff" },
        series: {
          states: { hover: { backgroundColor: null } },
          ...plotOptionsEvents,
        },
        pie: {
          // Semi-donut chart customization
          startAngle: graphType === "semidonut" ? -90 : 0,
          endAngle: graphType === "semidonut" ? 90 : 360,
          center: ["50%", graphType === "semidonut" ? "75%" : "50%"],
          size: "100%",
          innerSize: "70%",
          borderRadius: 6,
          dataLabels: { enabled: true, distance: 20 },
        },
        bar: {
          stacking: "normal",
          pointWidth: 25,
          borderRadius: 5,
        },
        ...(plotOptionsOptions || {}),
      },

      subtitle: showSubTitle
        ? {
            text: subtitleText,
            verticalAlign: "middle",
            floating: true,
            y: -10,
            style: { fontSize: "24px", fontWeight: "500", color: "#1F2B4D" },
            ...(subtitleOptions || {}),
          }
        : subtitleOptions && Object.keys(subtitleOptions).length
        ? subtitleOptions
        : undefined,
      credits: { enabled: false, ...(creditsOptions || {}) },
      legend: {
        enabled: !customLegend,
        symbolRadius: 2,
        layout: "horizontal",
        align: "center",
        verticalAlign: "bottom",
        itemDistance: 24,
        symbolPadding: 6,
        margin: 40,
        x: legendXPosition,
        y: legendYPosition,
        itemStyle: {
          color: "#60697D",
          fontFamily: "Manrope, sans-serif",
          fontSize: "12px",
          fontWeight: "500",
          lineHeight: "16px",
          padding: "20px",
        },
        itemHoverStyle: {
          color: "#0d152c",
        },
        navigation: {
          activeColor: "#3E576F",
          animation: true,
          arrowSize: 12,
        },
        ...(legendOptions || {}),
      },
      series: seriesOptions ?? seriesData,
      colorAxis:
        graphType === "heatmap" ||
        graphType === "bubble" ||
        graphType === "packedbubble" ||
        graphType === "treemap"
          ? {
              minColor: "#ffffff",
              maxColor: "#658EC4",
              ...(colorAxisOptions || {}),
            }
          : colorAxisOptions && Object.keys(colorAxisOptions).length
          ? colorAxisOptions
          : undefined,
      ...(additionalOptions || {}),
    }),
    [
      graphType,
      xAxisCategories,
      xAxisTitle,
      yAxisTitle,
      seriesData,
      stackedColumn,
      is3D,
      isExpanded,
      showScrollX,
      height,
      width,
      customLegend,
      titleOptions,
      xAxisOptions,
      yAxisOptions,
      yAxisLeftOptions,
      yAxisRightOptions,
      zAxisOptions,
      tooltipOptions,
      plotOptionsOptions,
      subtitleOptions,
      creditsOptions,
      legendOptions,
      colorAxisOptions,
      seriesOptions,
      additionalOptions,
    ]
  );

  return (
    <>
      {showchart ? (
        <div
          ref={containerRef}
          className={`chart-container ${isExpanded ? "expanded" : ""} ${
            isAnimating ? "animating" : ""
          } ${cardContainer ? "card-container" : ""} ${aboveChartComponent ? "above-chart-component" : ""}`}
          style={width ? { width: width } : {}}
        >
          {/* Header Section */}
          {showHeader && (
            <div className="chart-container-header">
              <div className="chart-container-header-title">
                <span className="chart-container-header-title-text">
                  {graphTitle}
                </span>
                {!!topLeftOptions && topLeftOptions !== null && (
                  <div className="divider-line" />
                )}
                {topLeftOptions && topLeftOptions}
              </div>

              <div className="chart-container-header-actions">
                {/* Optional Custom Header Options */}
                {topRightOptions && (
                  <div className="chart-custom-actions">
                    {React.isValidElement(topRightOptions)
                      ? topRightOptions
                      : null}
                  </div>
                )}

                {!!topRightOptions && topRightOptions !== null && (
                  <div className="divider-line" />
                )}

                {/* Toggle Table View */}
                {showSwitchButton && !isExpanded && (
                  <Tooltip title="Switch to Table" variant="tertiary">
                    <Button
                      variant="text"
                      icon={<TableChartOutlinedIcon />}
                      onClick={() => {
                        setShowChart(!showchart);
                      }}
                    />
                  </Tooltip>
                )}

                {/* Chart Type Selector Button */}
                {showChartTypeDropdown && (
                  <Tooltip title="Change chart type" variant="tertiary">
                    <Button
                      variant="text"
                      icon={<ChartDropdown />}
                      onClick={(event) => {
                        setShowChartList((prev) => !prev);
                        setSelectMenuAnchor(event.currentTarget);
                      }}
                    />
                  </Tooltip>
                )}

                {/* Download Button */}
                {showDownloadButton && (
                  <Tooltip title="Download" variant="tertiary">
                    <Button
                      variant="text"
                      icon={<FileDownloadOutlinedIcon />}
                      onClick={(event) => {
                        if (showDownloadMenu) {
                        setShowDownloadList((prev) => !prev);
                        setDownloadMenuAnchor(event.currentTarget);
                      } else {
                        onChartDownload(event);
                        }
                    }}
                    />
                  </Tooltip>
                )}
                {customSystemButton && customSystemButton}

                {/* Expand / Collapse Button */}
                {showExpandButton && (
                  <Tooltip title="Expand" variant="tertiary">
                    <Button
                      variant="text"
                      icon={isExpanded ? <Collapse /> : <ExpandIcon />}
                      onClick={() => {
                        if (isExpanded) exitFullscreen();
                        else enterFullscreen();
                      }}
                    />
                  </Tooltip>
                )}
              </div>
            </div>
          )}
          {aboveChartComponent && aboveChartComponent}

          {/* Chart Type Dropdown */}
          <Menu
            anchorEl={selectMenuAnchor}
            iconPlacement="left"
            onClose={() => {
              setShowChartList(false);
            }}
            open={showChartList}
            options={chartTypesOptions}
            selected={selectedChart}
            MenuProps={{
              transformOrigin: { vertical: "top", horizontal: "right" },
              anchorOrigin: { vertical: "bottom", horizontal: "right" },
            }}
            {...chartMenuProps}
          />

          {/* Download Options Dropdown */}
          {showDownloadMenu && (
            <Menu
              anchorEl={downloadMenuAnchor}
              iconPlacement="left"
              onClose={() => setShowDownloadList(false)}
              open={showDownloadList}
              options={[
                ...(showBuiltInDownloadOptions ? getBuiltInDownloadOptions() : []),
                ...downloadMenuOptions,
              ]}
              MenuProps={{
                transformOrigin: { vertical: "top", horizontal: "right" },
                anchorOrigin: { vertical: "bottom", horizontal: "right" },
              }}
            />
          )}
          {isEmpty ? (
            <div className="chart-empty-state">
             <EmptyStateImage />
              <span>No data to display</span>
            </div>
          ) : (
            <HighchartsReact
              highcharts={Highcharts}
              options={graphData}
              key={safeStringify(graphData, "graph") + isExpanded}
              ref={chartComponentRef}
            />
          )}
          {customLegend && (
            <div
              className="chart-custom-legend"
              style={{
                marginBottom: 12,
                marginTop: -32,
                ...(customLegendStyle || {}),
              }}
            >
              {React.isValidElement(customLegend)
                ? customLegend
                : typeof customLegend === "function"
                ? customLegend(chartComponentRef.current?.chart)
                : null}
            </div>
          )}
        </div>
      ) : (
        fallbackContent
      )}
    </>
  );
};
