import { useState, useRef, useEffect } from "react";
import Plot from "react-plotly.js";
import type { PlotData } from "./types";
import { Button, Card } from "@elvis/ui";

interface OptimizationPlotProps {
  data: PlotData;
  isLoading: boolean;
  xlim: [number, number];
  ylim: [number, number];
  setAxisLimits: (xlim: [number, number], ylim: [number, number]) => void;
}

export default function OptimizationPlot({ data, isLoading, xlim, ylim, setAxisLimits }: OptimizationPlotProps) {

  // data
  let x: number[] = data.functionValues ? data.functionValues.x : [];
  let y: number[] = data.functionValues ? data.functionValues.y : [];
  let z: number[][] = data.functionValues && data.functionValues.z ? data.functionValues.z : [];

  let trajX: number[] = data.trajectoryValues ? data.trajectoryValues.x : [];
  let trajY: number[] = data.trajectoryValues ? data.trajectoryValues.y : [];
  let trajZ: number[] = data.trajectoryValues && data.trajectoryValues.z ? data.trajectoryValues.z : [];
  
  const [colorScaleRange, setColorScaleRange] = useState<[number, number] | null>(null);
  const nextColorScaleRangeRef = useRef<[number, number] | null>(null);

  useEffect(() => {
    if (z) {
      if (!z || z.length === 0) {
        nextColorScaleRangeRef.current = null;
        return;
      }

      let zMin = Infinity;
      let zMax = -Infinity;

      for (let i = 0; i < z.length; i++) {
        for (let j = 0; j < z[i].length; j++) {
          const v = z[i][j];
          if (!Number.isFinite(v)) {
            continue;
          }
          if (v < zMin) {
            zMin = v;
          }
          if (v > zMax) {
            zMax = v;
          }
        }
      }

      const padding = (zMax - zMin) * 0.1;
      nextColorScaleRangeRef.current = [zMin - padding, zMax + padding];

      if (colorScaleRange === null) {
        setColorScaleRange(nextColorScaleRangeRef.current);
      }
    }
  }, [z]);

  function updateColorScaleRange() {
    if (nextColorScaleRangeRef.current) {
      setColorScaleRange(nextColorScaleRangeRef.current);
      nextColorScaleRangeRef.current = null;
    }
  }

  const plotRef = useRef<any>(null);
  const layoutRef = useRef<any>({
    dragmode: 'pan',
    showlegend: false,
    xaxis: {
      title: { text: 'x' },
      range: xlim,
    },
    yaxis: {
      title: { text: 'y' },
      range: ylim,
    },
    margin: { t: 40, r: 40, b: 40, l: 40 }
  })

  const hasNoData = !data.functionValues && !data.trajectoryValues;

  if (isLoading && hasNoData) {
    return (
      <Card className="min-h-[320px] flex items-center justify-center p-6">
        <div className="text-center">
          <div className="text-lg font-medium">Loading...</div>
        </div>
      </Card>
    );
  }

  if (z.length === 0) {
    return (
      <Card className="min-h-[320px]">
        <Plot
          ref={plotRef}
          onRelayout={(event) => {
            const x0 = event['xaxis.range[0]'];
            const x1 = event['xaxis.range[1]'];
            const y0 = event['yaxis.range[0]'];
            const y1 = event['yaxis.range[1]'];

            if (
              typeof x0 === "number"
              && typeof x1 === "number"
              && typeof y0 === "number"
              && typeof y1 === "number"
            ) {
              setAxisLimits([x0, x1], [y0, y1]);
            }
          }}
          data={[
            {
              x: x,
              y: y,
              type: 'scatter',
              mode: 'lines',
              line: { color: '#1f77b4', width: 2 },
              hoverinfo: "skip",
            },
            {
              x: trajX,
              y: trajY,
              type: 'scatter',
              mode: 'lines+markers',
              line: { color: '#d97871', width: 2 },
              marker: { color: '#d97871', size: 10 },
              hoverinfo: "skip",
            },
            {
              x: trajX.length > 0 ? [trajX.at(-1)!] : [],
              y: trajY.length > 0 ? [trajY.at(-1)!] : [],
              type: 'scatter',
              mode: 'markers',
              marker: { color: 'red', size: 12 },
              hoverinfo: "skip",
            }
          ]}
          layout={layoutRef.current}
          style={{ width: '100%', height: '100%' }}
          config={{ 
            responsive: true,
            displayModeBar: true,
            scrollZoom: true,
          }}
        />
      </Card>
    );
  } else {
    return (
      <Card className="flex flex-col min-h-[420px]">
        <Plot
          ref={plotRef}
          onRelayout={(event) => {
            const x0 = event['xaxis.range[0]'];
            const x1 = event['xaxis.range[1]'];
            const y0 = event['yaxis.range[0]'];
            const y1 = event['yaxis.range[1]'];

            if (
              typeof x0 === "number"
              && typeof x1 === "number"
              && typeof y0 === "number"
              && typeof y1 === "number"
            ) {
              setAxisLimits([x0, x1], [y0, y1]);
            }
          }}
          data={[
            {
              x: x,
              y: y,
              z: z,
              zmin: colorScaleRange?.[0],
              zmax: colorScaleRange?.[1],
              type: 'contour',
              colorscale: 'Viridis',
              hoverinfo: "skip",
              contours: {
                coloring: "heatmap",
                showlines: false,
              }
            },
            {
              x: trajX,
              y: trajY,
              z: trajZ,
              type: 'scatter',
              mode: 'lines+markers',
              line: { color: '#d97871', width: 2 },
              marker: { color: '#d97871', size: 10 },
              hoverinfo: "skip",
            },
            {
              x: trajX.length > 0 ? [trajX.at(-1)!] : [],
              y: trajY.length > 0 ? [trajY.at(-1)!] : [],
              z: trajZ.length > 0 ? [trajZ.at(-1)!] : [],
              type: 'scatter',
              mode: 'markers',
              marker: { color: 'red', size: 12 },
              hoverinfo: "skip",
            }
          ]}
          layout={layoutRef.current}
          className="w-full flex-1"
          config={{ 
            responsive: true,
            displayModeBar: false,
            scrollZoom: true,
          }}
        />
        <div className="mt-2 flex justify-end">
          <Button label="Update Color Scale" onClick={updateColorScaleRange} />
        </div>
      </Card>
    ); 
  }
}
