import { colors } from "@mui/material";
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
import { useEffect, useState } from "react";
import { distanceConversion } from "utils";

interface Props {
  bin: jsonBin;
}

interface svgPoint {
  x: number;
  y: number;
}

export default function SideView(props: Props) {
  const svgViewBoxSize = 250;
  //percentage to of the svg to be the bin drawing from 0 to 1,
  //NOTE: this is the percentage based on the longest side
  //ie. if the bin is taller than it is wide the bin will be x percent of the height of the viewbox and the width will be scaled to the height and vice versa
  const scaleMultiplier = 0.8;
  const nodeSpacing = 4; //space in feet between the nodes
  const dimensionFontSize = 7;
  const gapSize = svgViewBoxSize * 0.05;
  const { bin } = props;
  const [scale, setScale] = useState(0); //the scale to multiply the bin dimension by in order to determine how long to draw the line
  const [hopperHeight, setHopperHeight] = useState(0);
  const [roofHeight, setRoofHeight] = useState(0);

  useEffect(() => {
    //get the peak height of the hopper
    let h = (bin.Diameter / 2) * Math.tan(bin.HopperAngle * (Math.PI / 180));
    setHopperHeight(h);
    setRoofHeight(bin.Peak - bin.Sidewall);

    let heightscale = svgViewBoxSize / (bin.Peak + h);
    let widthscale = svgViewBoxSize / bin.Diameter;

    //need to use the scale of the longer of the two dimensions
    setScale((heightscale < widthscale ? heightscale : widthscale) * scaleMultiplier);
  }, [bin, svgViewBoxSize]);

  const binOutline = () => {
    let startX = svgViewBoxSize / 2;
    let startY = 0;
    //let paddingVal = (padding * svgViewBoxSize)

    return (
      <path
        strokeWidth={2}
        stroke={colors.grey[400]}
        fillOpacity={0}
        d={
          "M " +
          startX +
          " " +
          startY + //starting point
          " L " +
          (startX + (bin.Diameter / 2) * scale) +
          " " +
          roofHeight * scale + //right side of the bin roof
          " V " +
          (roofHeight + bin.Sidewall) * scale + //right sidewall
          (hopperHeight === 0
            ? " H " + (startX - (bin.Diameter / 2) * scale) //bin bottom if there is no hopper
            : //else
              " L " +
              startX +
              " " +
              (roofHeight + hopperHeight + bin.Sidewall) * scale + //right side of the hopper
              " L " +
              (startX - (bin.Diameter / 2) * scale) +
              " " +
              (roofHeight + bin.Sidewall) * scale) + //left side of the hopper
          " V " +
          roofHeight * scale + //left sidewall
          " Z " //left side of the bin roof (Z command draws the line from where you currently are back to the startign point)
        }
      />
    );
  };

  const cableLines = () => {
    let cables: JSX.Element[] = [];
    //let paddingVal = (padding * svgViewBoxSize)

    // line for the roof at the top of the sidewall
    // cables.push(
    //     <line
    //         key={"roof"}
    //         strokeWidth={2}
    //         stroke="yellow"
    //         x1={0}
    //         strokeDasharray={3}
    //         x2={svgViewBoxSize}
    //         y1={roofHeight*scale + paddingVal}
    //         y2={roofHeight*scale + paddingVal}
    //     />
    // )

    bin.CableSums.forEach(sum => {
      let cableLength = 0;
      bin.Cables.forEach(c => {
        if (sum.Orbit === c.Orbit) {
          //numNodes = c.Nodes
          cableLength = c.Length;
        }
      });
      let numNodes = Math.ceil(cableLength / nodeSpacing);

      let xVal = svgViewBoxSize / 2 + sum.DistanceFromCenter * scale;
      let cableStart = sum.DistanceFromCenter * Math.tan(bin.RoofAngle * (Math.PI / 180)) * scale;
      //need to offset the padding to the top since we are now below the half mark as well as pad the bottom
      let cableEnd = cableStart + cableLength * scale;

      cables.push(
        <line
          key={"orbit" + sum.Orbit}
          strokeWidth={2}
          stroke="yellow"
          x1={xVal}
          y1={cableStart}
          x2={xVal}
          y2={cableEnd}
        />
      );

      let svgSpacing = (cableEnd - cableStart) / numNodes;

      for (let i = 0; i < numNodes; i++) {
        let nodeY = cableEnd - svgSpacing * i;
        cables.push(
          <circle key={"orbit" + sum.Orbit + "node" + i} cx={xVal} cy={nodeY} r={2} fill="blue" />
        );
      }
    });
    return cables;
  };

  const dimensionText = (key: string, x: number, y: number, text: string) => {
    return (
      <text
        key={key}
        style={{ fontSize: dimensionFontSize, fill: "white" }}
        x={x}
        y={y}
        textAnchor="middle"
        dominantBaseline={"middle"}>
        {text}
      </text>
    );
  };

  const dimensionPath = (key: string, start: svgPoint, corner: svgPoint, end: svgPoint) => {
    return (
      //<line key={key} strokeWidth={1} stroke="white" x1={x1} x2={x2 ?? x1} y1={y1} y2={y2 ?? y1} />
      <path
        key={key}
        strokeWidth={1}
        stroke="white"
        fillOpacity={0}
        d={
          "M " +
          start.x +
          " " +
          start.y +
          "L " +
          corner.x +
          " " +
          corner.y +
          "L " +
          end.x +
          " " +
          end.y
        }
      />
    );
  };

  const bottomDiameter = () => {
    let d: JSX.Element[] = [];

    let x1 = svgViewBoxSize / 2 - (bin.Diameter / 2) * scale;
    let x2 = svgViewBoxSize / 2 + (bin.Diameter / 2) * scale;

    let y1 =
      (roofHeight + bin.Sidewall + hopperHeight) * scale +
      svgViewBoxSize * (1 - scaleMultiplier) * 0.1;
    let y2 =
      (roofHeight + bin.Sidewall + hopperHeight) * scale +
      svgViewBoxSize * (1 - scaleMultiplier) * 0.25;

    d.push(
      dimensionText(
        "bottomText",
        svgViewBoxSize / 2,
        y2,
        distanceConversion(bin.Diameter).toFixed(1)
      )
    );

    d.push(
      dimensionPath(
        "bottomDiameterLine1",
        { x: x1, y: y1 },
        { x: x1, y: y2 },
        { x: svgViewBoxSize / 2 - gapSize, y: y2 }
      )
    );
    d.push(
      dimensionPath(
        "bottomDiameterLine2",
        { x: svgViewBoxSize / 2 + gapSize, y: y2 },
        { x: x2, y: y2 },
        { x: x2, y: y1 }
      )
    );

    return d;
  };

  //height of the sidewall, on the left side - always used
  const sidwallDimension = () => {
    let d: JSX.Element[] = [];
    let centerX = svgViewBoxSize / 2;
    let x1 = centerX - (bin.Diameter / 2) * scale - svgViewBoxSize * (1 - scaleMultiplier) * 0.1;

    let x2 = x1 - svgViewBoxSize * (1 - scaleMultiplier) * 0.15;
    let midpoint = (roofHeight + bin.Sidewall / 2) * scale;

    let y1 = roofHeight * scale;
    let y2 = (roofHeight + bin.Sidewall) * scale;

    d.push(
      dimensionText("sidewallText", x2, midpoint, distanceConversion(bin.Sidewall).toFixed(1))
    );
    d.push(
      dimensionPath(
        "sidwallTopLine",
        { x: x1, y: y1 },
        { x: x2, y: y1 },
        { x: x2, y: midpoint - gapSize }
      )
    );
    d.push(
      dimensionPath(
        "sidewallbottomLine",
        { x: x2, y: midpoint + gapSize },
        { x: x2, y: y2 },
        { x: x1, y: y2 }
      )
    );
    return d;
  };

  //height of the bottom of the sidewall to the peak of the bin, on the left side - only used for hopper bins
  const peakDimension = () => {
    let d: JSX.Element[] = [];
    let centerX = svgViewBoxSize / 2;
    let xWall = centerX - (bin.Diameter / 2) * scale - svgViewBoxSize * (1 - scaleMultiplier) * 0.1;
    let xPeak = svgViewBoxSize / 2 - svgViewBoxSize * (1 - scaleMultiplier) * 0.1;

    let xText = xWall - svgViewBoxSize * (1 - scaleMultiplier) * 0.5;
    let midpoint = ((roofHeight + bin.Sidewall) / 2) * scale;

    let yTop = 0;
    let yBottom = (roofHeight + bin.Sidewall) * scale;

    d.push(
      dimensionText(
        "peakText",
        xText,
        midpoint,
        distanceConversion(bin.Sidewall + roofHeight).toFixed(1)
      )
    );
    d.push(
      dimensionPath(
        "peakTopLine",
        { x: xPeak, y: yTop },
        { x: xText, y: yTop },
        { x: xText, y: midpoint - gapSize }
      )
    );
    d.push(
      dimensionPath(
        "peakbottomLine",
        { x: xText, y: midpoint + gapSize },
        { x: xText, y: yBottom },
        { x: xWall, y: yBottom }
      )
    );

    return d;
  };

  //total height of the bin, on the right side - always used
  const totalDimension = () => {
    let d: JSX.Element[] = [];
    let centerX = svgViewBoxSize / 2;
    //let paddingVal = (padding* svgViewBoxSize)
    let binRightX = centerX + (bin.Diameter / 2) * scale;

    let xBinCenter = centerX + svgViewBoxSize * (1 - scaleMultiplier) * 0.1;
    let xBinWall = binRightX + svgViewBoxSize * (1 - scaleMultiplier) * 0.1;
    let x2 = binRightX + svgViewBoxSize * (1 - scaleMultiplier) * 0.2;
    let midpoint = ((roofHeight + bin.Sidewall + hopperHeight) / 2) * scale;

    let y1 = 0;
    let y2 = (roofHeight + bin.Sidewall + hopperHeight) * scale;

    d.push(
      dimensionText(
        "totalText",
        x2,
        midpoint,
        distanceConversion(roofHeight + bin.Sidewall + hopperHeight).toFixed(1)
      )
    );
    d.push(
      dimensionPath(
        "totalTopLine",
        { x: xBinCenter, y: y1 },
        { x: x2, y: y1 },
        { x: x2, y: midpoint - gapSize }
      )
    );
    d.push(
      dimensionPath(
        "totalBottomLine",
        { x: x2, y: midpoint + gapSize },
        { x: x2, y: y2 },
        { x: hopperHeight > 0 ? xBinCenter : xBinWall, y: y2 }
      )
    );

    return d;
  };

  const binDimensions = () => {
    let dimensions: JSX.Element[] = [];

    dimensions.push(...bottomDiameter());
    // sidwall Height
    dimensions.push(...sidwallDimension());
    //total bin height
    dimensions.push(...totalDimension());
    if (hopperHeight > 0) {
      //show the height of the peak + sidwall without the hopper
      dimensions.push(...peakDimension());
    }

    return dimensions;
  };

  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox={
        "0 " +
        (svgViewBoxSize * (scaleMultiplier - 1)) / 2 +
        " " +
        svgViewBoxSize +
        " " +
        svgViewBoxSize
      }
      height="100%"
      width="100%">
      {cableLines()}
      {binOutline()}
      {binDimensions()}
    </svg>
  );
}
