'use client';

import {
  useState,
  useEffect,
  PropsWithChildren,
  ReactNode,
  SetStateAction,
  Dispatch,
  ChangeEventHandler,
  ForwardedRef,
  forwardRef,
  useRef,
} from 'react';

import { useMediaQuery } from 'react-responsive';

import { updateComputationResultEWS } from '@/redux/computationsEWSSlice';
import { useAppSelector, useAppDispatch } from '@/redux/hooks';

import type Polygon from '@arcgis/core/geometry/Polygon';

import Warning from '@/app/components/warning';

import { initializeCalculationsMenuHandlers } from './potenzialkarte';
import { calculateGrid } from './gridcomputer';

const InputSection = (props: { children: ReactNode }) => {
  return <div className="pb-2">{props.children}</div>;
};

type Properties = {
  isLoading: Dispatch<SetStateAction<boolean>>;
};

type Resource = { layerId: number; layerName: string; feature: any };

const css =
  'peer block min-h-[auto] w-full border px-3 py-1 leading-normal outline-none transition-all duration-200 ease-linear motion-reduce:transition-none';

export default forwardRef(function CalculationsMenu(
  { isLoading }: PropsWithChildren<Properties>,
  outerRef: ForwardedRef<HTMLDivElement> | undefined
) {
  const isTablet = useMediaQuery({ maxWidth: 1024 });

  const [polygon, setPolygon] = useState<Polygon | null>(null);
  const [gridSpacing, setGridSpacing] = useState<number>(10);
  const [boreDepth, setBoreDepth] = useState<number>(100);
  const [BS_HZ, setBS_HZ] = useState<number>(-1);
  const [BS_KL, setBS_KL] = useState<number>(-1);
  const [P_KL, setP_KL] = useState<number>(-1);
  const [P_HZ, setP_HZ] = useState<number>(-1);
  const [points, setPoints] = useState<number[][]>([]);
  const [heating, setHeating] = useState<number>(35);
  const [opened, setOpened] = useState<boolean>(true);

  const innerRef = useRef<HTMLDivElement | null>(null);

  const cadastralData = useAppSelector((store) => store.cadastre.value);
  const resources: Resource[] = useAppSelector((store) => store.resourcesEWS.value);

  const dispatch = useAppDispatch();

  // run python script with values from layers
  const handlePythonCalculation = () => {
    if (cadastralData && resources && points.length <= 300 && polygon) {
      isLoading(true);

      let pointsText = JSON.stringify(points);

      const BT = parseFloat(
        resources.find((result) => result.layerId === 0)?.feature?.attributes['Classify.Pixel Value']
      );
      const GT = parseFloat(
        resources.find((result) => result.layerId === 1)?.feature?.attributes['Classify.Pixel Value']
      );
      const WLF = parseFloat(
        resources.find((result) => result.layerId === 2)?.feature?.attributes['Classify.Pixel Value']
      );

      const BS_HZ_Norm = parseInt(
        resources.find((result) => result.layerId === 7)?.feature?.attributes['Classify.Pixel Value']
      );
      const BS_KL_Norm = parseInt(
        resources.find((result) => result.layerId === 8)?.feature?.attributes['Classify.Pixel Value']
      );

      let url = '/api';

      const data = {
        BT,
        GT,
        WLF,
        BS_HZ_Norm,
        BS_KL_Norm,
        BS_HZ: BS_HZ === -1 ? 0 : BS_HZ,
        BS_KL: BS_KL === -1 ? 0 : BS_KL,
        P_HZ: P_HZ === -1 ? 0 : P_HZ,
        P_KL: P_KL === -1 ? 0 : P_KL,
        boreDepth,
        points: pointsText,
        heating,
      };

      if (
        Object.values(data).every((x) => typeof x !== 'undefined' && x !== null) &&
        !isNaN(BT) &&
        !isNaN(GT) &&
        !isNaN(WLF) &&
        !isNaN(BS_HZ_Norm) &&
        !isNaN(BS_KL_Norm)
      ) {
        fetch(url, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data),
        })
          .then((res) => res.json())
          .then((data) => {
            // user defined input
            const calculationMode = data[0];
            const P_HZ_user = parseFloat(data[1]);
            const P_KL_user = -parseFloat(data[2]);
            const E_HZ_user = parseFloat(data[3]) / 1000;
            const E_KL_user = -(parseFloat(data[4]) / 1000);
            const cover = parseInt(data[5]);
            const Pel_heatpump_user = parseFloat(data[6]);
            const Pel_chiller_user = -parseFloat(data[7]);
            const Eel_heatpump_user = parseFloat(data[8]) / 1000;
            const Eel_chiller_user = -parseFloat(data[9]) / 1000;
            const COP = parseFloat(data[15]);
            const EER = parseFloat(data[16]);
            const SCOP = parseFloat(data[17]);
            const SEER = parseFloat(data[18]);
            const Efactor_user = parseFloat(data[19]);
            const imagehash = 'data:image/png;base64,' + data[20];
            const imagehashSondenfeld = 'data:image/png;base64,' + data[21];
            const GTcalc = parseFloat(data[22]);
            const heizleistung = P_HZ_user + Pel_heatpump_user;
            const heizarbeit = E_HZ_user + Eel_heatpump_user;
            const kuehlleistung = P_KL_user - Pel_chiller_user;
            const kuehlarbeit = E_KL_user - Eel_chiller_user;
            // automatically balanced
            const balanced = parseInt(data[23]);
            const P_HZ_bal = parseFloat(data[24]);
            const P_KL_bal = -parseFloat(data[25]);
            const E_HZ_bal = parseFloat(data[26]) / 1000;
            const E_KL_bal = -parseFloat(data[27]) / 1000;
            const cover_bal = parseInt(data[28]);
            const Pel_heatpump_bal = parseFloat(data[29]);
            const Pel_chiller_bal = -parseFloat(data[30]);
            const Eel_heatpump_bal = parseFloat(data[31]) / 1000;
            const Eel_chiller_bal = -parseFloat(data[32]) / 1000;
            const meanBoreholeSpacing = parseFloat(data[36]);
            const cover_rise = parseFloat(data[37]);
            const COP_bal = parseFloat(data[38]);
            const EER_bal = parseFloat(data[39]);
            const SCOP_bal = parseFloat(data[40]);
            const SEER_bal = parseFloat(data[41]);
            const Efactor_bal = parseFloat(data[42]);
            const imagehashBal = 'data:image/png;base64,' + data[43];
            const BS_HZ_bal = parseFloat(data[44]);
            const BS_KL_bal = parseFloat(data[45]);
            const T_radiator = parseInt(data[46]);
            const heizleistungBal = P_HZ_bal + Pel_heatpump_bal;
            const heizarbeitBal = Eel_heatpump_bal + E_HZ_bal;
            const kuehlleistungBal = P_KL_bal - Pel_chiller_bal;
            const kuehlarbeitBal = E_KL_bal - Eel_chiller_bal;
            dispatch(
              updateComputationResultEWS({
                calculationMode,
                points: points.length,
                meanBoreholeSpacing,
                boreDepth,
                P_HZ,
                P_KL,
                BS_HZ,
                BS_KL,
                BS_HZ_Norm,
                BS_KL_Norm,
                P_HZ_user,
                P_KL_user,
                Pel_heatpump_user,
                Pel_chiller_user,
                E_HZ_user,
                E_KL_user,
                Efactor_user,
                Eel_heatpump_user,
                Eel_chiller_user,
                cover,
                imagehash,
                imagehashSondenfeld,
                balanced,
                P_HZ_bal,
                P_KL_bal,
                Pel_heatpump_bal,
                Pel_chiller_bal,
                Eel_heatpump_bal,
                Efactor_bal,
                E_HZ_bal,
                cover_bal,
                imagehashBal,
                heizleistung,
                heizarbeit,
                kuehlleistung,
                kuehlarbeit,
                heizleistungBal,
                heizarbeitBal,
                kuehlleistungBal,
                GTcalc,
                COP,
                SCOP,
                EER,
                SEER,
                BS_HZ_bal,
                BS_KL_bal,
                COP_bal,
                EER_bal,
                E_KL_bal,
                SEER_bal,
                SCOP_bal,
                Eel_chiller_bal,
                kuehlarbeitBal,
                cover_rise,
                T_radiator,
              })
            );
            isLoading(false);
          })
          .catch((err) => {
            dispatch(
              updateComputationResultEWS({
                error: JSON.stringify(err),
              })
            );
          });
      } else {
        dispatch(
          updateComputationResultEWS({
            error: 'Aufgrund ungültiger Daten ist für dieses Grundstück keine Berechnung möglich.',
          })
        );
        isLoading(false);
      }
    }
  };

  useEffect(() => {
    // initialize callback functions
    initializeCalculationsMenuHandlers(setPoints, setPolygon);

    // cleanup
    return () => {
      // set polygon to null
      setPolygon(null);
    };
  }, []);

  // reset state
  useEffect(() => {
    setGridSpacing(10);
  }, [polygon]);

  const handleGridSpacing: ChangeEventHandler<HTMLInputElement> = (event) => {
    let value = parseInt((event.target as HTMLInputElement).value);
    if (value < 5) {
      value = 5;
    } else if (value > 15) {
      value = 15;
    }

    setGridSpacing(value);
    calculateGrid(polygon, value, setPoints);
  };

  const handleDepth: ChangeEventHandler<HTMLInputElement> = (event) => {
    let value = parseInt((event.target as HTMLInputElement).value);
    if (value > 250) {
      value = 250;
    } else if (value < 80) {
      value = 80;
    }
    setBoreDepth(value);
  };

  const handleBS_HZ: ChangeEventHandler<HTMLInputElement> = (event) => {
    let value = parseInt((event.target as HTMLInputElement).value);
    if (value > 4379 || value < 0) {
      value = -1;
    }

    if (value !== -1) {
      setBS_HZ(value);
    }
  };

  const handleBS_KL: ChangeEventHandler<HTMLInputElement> = (event) => {
    let value = parseInt((event.target as HTMLInputElement).value);
    if (event.target && event.target !== null) {
      if (value > 4379 || value < 0) {
        value = -1;
      }

      if (value !== -1) {
        setBS_KL(value);
      }
    }
  };

  const handleP_HZ: ChangeEventHandler<HTMLInputElement> = (event) => {
    let value = parseInt((event.target as HTMLInputElement).value);
    if (value < 0) {
      value = -1;
    }

    if (value !== -1) {
      setP_HZ(value);
    }
  };

  const handleP_KL: ChangeEventHandler<HTMLInputElement> = (event) => {
    let value = parseInt((event.target as HTMLInputElement).value);
    if (value < 0) {
      value = -1;
    }

    if (value !== -1) {
      setP_KL(value);
    }
  };

  const handleKeyDown = (event: any) => {
    event.preventDefault();
  };

  const handleHeating: ChangeEventHandler<HTMLSelectElement> = (event) => {
    let value = parseInt((event.target as HTMLSelectElement).value);
    setHeating(value);
  };

  const handleClick = () => {
    setOpened(!opened);
    if (innerRef && innerRef.current) {
      innerRef.current.classList.toggle('hidden');
    }
  };

  return (
    <div
      className={`absolute top-[70px] lg:top-24 left-4 ${
        opened && isTablet ? 'bottom-12' : ''
      } w-[calc(100%-2rem)] lg:w-[300px] z-0`}
    >
      <div
        onClick={handleClick}
        className="bg-gray-700 text-white cursor-pointer p-4 w-full border-0 hover:bg-gray-500 h-12 items-center justify-between text-sm xl:text-base z-0"
      >
        Berechnungsmenü <span className="float-right">{opened ? '-' : '+'}</span>
      </div>
      <div
        className={`h-[calc(100%-3rem)] px-2 xl:px-4 pt-4 pb-2 overflow-y-auto bg-white text-sm ${
          opened ? '' : 'hidden'
        }`}
        ref={innerRef}
      >
        <div className={!polygon ? 'bg-white opacity-50 pointer-events-none pb-2' : 'pb-2'}>
          <label>Sondenpunkte auswählen/zeichnen</label>
          <div ref={outerRef}></div>
        </div>
        <InputSection>
          <label htmlFor="gridspacing-input">Heizungsart </label>
          <select id="gridspacing-input" onChange={handleHeating} className={css} disabled={polygon ? false : true}>
            <option value={35}>Fußbodenheizung</option>
            <option value={50}>Radiator</option>
          </select>
        </InputSection>
        <InputSection>
          <label htmlFor="gridspacing-input">Sondenabstand in Meter</label>
          <input
            type="number"
            value={gridSpacing}
            className={css}
            onChange={handleGridSpacing}
            onKeyDown={handleKeyDown}
            placeholder="Wert zwischen 15 und 15 m (default=100)"
            min="5"
            max="15"
            disabled={polygon ? false : true}
          ></input>
        </InputSection>
        <InputSection>
          <label htmlFor="depth-input">Sondentiefe in Meter</label>
          <input
            className={css}
            type="number"
            min="80"
            max="250"
            placeholder="Wert zwischen 80 und 250 m (default=100)"
            value={boreDepth}
            onChange={handleDepth}
            onKeyDown={handleKeyDown}
            disabled={polygon ? false : true}
          ></input>
        </InputSection>
        <InputSection>
          <label htmlFor="phz-input">Heizleistung in kW (optional)</label>
          <input
            className={css}
            type="number"
            min="0"
            placeholder="Wert größer 0"
            onChange={handleP_HZ}
            value={P_HZ === -1 ? '' : P_HZ}
            disabled={polygon ? false : true}
          ></input>
        </InputSection>
        <InputSection>
          <label htmlFor="pkl-input">Kühlleistung in kW (optional)</label>
          <input
            className={css}
            type="number"
            min="0"
            placeholder="Wert größer 0"
            onChange={handleP_KL}
            value={P_KL === -1 ? '' : P_KL}
            disabled={polygon ? false : true}
          ></input>
        </InputSection>
        <InputSection>
          <label htmlFor="bshz-input">Jahresbetriebsstunden Heizen (optional)</label>
          <input
            className={css}
            type="number"
            min="0"
            max="4379"
            placeholder="Wert zwischen 0 und 4379"
            onChange={handleBS_HZ}
            value={BS_HZ === -1 ? '' : BS_HZ}
            disabled={polygon ? false : true}
          ></input>
        </InputSection>
        <InputSection>
          <label htmlFor="bskl-input">Jahresbetriebsstunden Kühlen (optional)</label>
          <input
            type="number"
            min="0"
            max="4379"
            placeholder="Wert zwischen 0 und 4379"
            onChange={handleBS_KL}
            value={BS_KL === -1 ? '' : BS_KL}
            className={css}
            disabled={polygon ? false : true}
          ></input>
        </InputSection>
        {(P_HZ > 0 || P_KL > 0 || BS_HZ > 0 || BS_KL > 0) &&
        (P_HZ === -1 || P_KL === -1 || BS_HZ === -1 || BS_KL === -1) ? (
          <Warning>Solange nicht alle Parameter ausgefüllt sind, wird mit Normwerten gerechnet.</Warning>
        ) : null}
        {points.length > 300 && <Warning>Es sind maximal 300 Punkte möglich. Bitte löschen Sie zuerst Punkte.</Warning>}
        {polygon && points.length === 0 ? <Warning>Zeichnen Sie mindestens einen Punkt!</Warning> : null}
        <div className=" p-px w-full">
          <button
            onClick={handlePythonCalculation}
            className={
              polygon && points.length > 0 && points.length <= 300
                ? 'w-full h-10 border-none bg-gray-700 hover:bg-gray-500 text-white mb-2 py-2 px-4 cursor-pointer'
                : 'w-full h-10 border-none bg-gray-700 hover:bg-gray-500 text-white mb-2 py-2 px-4 opacity-50 cursor-not-allowed'
            }
            disabled={polygon && points.length > 0 && points.length <= 300 ? false : true}
          >
            Berechnung starten
          </button>
        </div>
      </div>
    </div>
  );
});
