import React, {
  useCallback,
  useEffect,
  useLayoutEffect,
  useMemo,
  useRef,
  useState,
} from "react";

import styled, { css, keyframes } from "styled-components";
import "./styles.css";
import { distanceBetweenPoints } from "../ecg/canvas-functions";
import { useDrawDerivations } from "../hooks/useDrawDerivations";

import ECG from "./ECG";
import EcgNavigator from "./EcgNavigator";
import SkeletonContainer from "./SkeletonContainer";
import AddCommentDialog from "./comments/dialogs/AddCommentDialog";

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCommentAlt } from "@fortawesome/free-solid-svg-icons";

import { useComments } from "../hooks/useComments";

import { FinishSecondEcgComponent } from "./FinishSecondEcgComponent";

import global_es from "../translations/es/global.json";
import global_pt from "../translations/pt/global.json";

import i18next from "i18next";
import { I18nextProvider } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { ButtonContinue } from "./ButtonContinue";
import { ButtonAdd } from "./ButtonAdd";
import {
  getPixelsFromViewerToPlayer,
  getSecondsFromPixels,
} from "./comments/utils/date";

i18next.use(LanguageDetector).init({
  detection: {
    order: ["querystring", "localStorage", "sessionStorage", "navigator"],
    lookupQuerystring: "lng",
    lookupLocalStorage: "language",
    lookupSessionStorage: "",
  },
  interpolation: { escapeValue: false },
  fallbackLng: "es",
  resources: {
    es: {
      global: global_es,
    },
    pt: {
      global: global_pt,
    },
  },
});

const PanelRoot = styled.div`
  width: 100%;
  box-sizing: border-box;
`;

const PanelShell = styled.div`
  display: grid;
  grid-template-columns: ${({ $compact }) =>
    $compact ? "minmax(0, 1fr)" : "auto minmax(0, 1fr)"};
  gap: ${({ $gap }) => `${$gap}px`};
  align-items: start;
  width: 100%;
`;

const ControlRail = styled.div`
  display: flex;
  justify-content: ${({ $compact }) => ($compact ? "flex-start" : "center")};
  align-items: flex-start;
`;

const ControlButtonFrame = styled.div`
  border-radius: 24px;
  padding: 10px;
  background: linear-gradient(180deg, #ffffff 0%, #fbfbff 100%);
  border: 1px solid rgba(0, 79, 236, 0.08);
  box-shadow: 0 20px 40px rgba(48, 55, 85, 0.08);
`;

const ContentColumn = styled.div`
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 18px;
`;

const ECGCard = styled.div`
  position: relative;
  min-width: 0;
  border-radius: 28px;
  padding: ${({ $padding }) => `${$padding}px`};
  background: linear-gradient(180deg, #ffffff 0%, #fbfbff 100%);
  border: 1px solid rgba(177, 99, 255, 0.12);
  box-shadow: 0 28px 56px rgba(48, 55, 85, 0.08);
  overflow: hidden;
`;

const PlayerSurface = styled.div`
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 18px;
  filter: ${({ $muted }) => ($muted ? "blur(7px)" : "none")};
  transition: filter 0.2s ease;
`;

const ECGScrollArea = styled.div`
  display: flex;
  flex-direction: column;
  gap: ${({ $rowGap = ECG_ROW_GAP }) => `${$rowGap}px`};
  min-width: 0;
  height: ${({ $height }) => `${$height}px`};
  max-height: 100%;
  overflow-x: hidden;
  overflow-y: auto;
  padding: 0 4px 4px 0;
  box-sizing: border-box;

  ::-webkit-scrollbar {
    width: 7px;
  }

  ::-webkit-scrollbar-thumb {
    border-radius: 999px;
    background: rgba(0, 79, 236, 0.18);
  }
`;

const PinnedWrapper = styled.div`
  display: flex;
  justify-content: center;
`;

const NavigatorSection = styled.div`
  display: flex;
  justify-content: center;
`;

const ActionRow = styled.div`
  display: flex;
  justify-content: center;
`;

const SkeletonOverlay = styled.div`
  position: absolute;
  inset: ${({ $padding }) => `${$padding}px`};
  display: flex;
  align-items: stretch;
  justify-content: stretch;
  pointer-events: none;
`;

const pulse = keyframes`
  0% {
    transform: scale(0.96);
    box-shadow: 0 0 0 0 rgba(0, 79, 236, 0.22);
  }

  70% {
    transform: scale(1);
    box-shadow: 0 0 0 12px rgba(0, 79, 236, 0);
  }

  100% {
    transform: scale(0.96);
    box-shadow: 0 0 0 0 rgba(0, 79, 236, 0);
  }
`;

const ECGButton = styled.button`
  position: relative;
  width: ${({ repository }) => (repository === "frontMulti" ? "50px" : "42px")};
  height: ${({ repository }) =>
    repository === "frontMulti" ? "50px" : "42px"};
  color: white;
  background: #004fec;
  border: none;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  animation: ${(props) =>
    props.continuesecondtocomments || props.secondcheck
      ? css`none`
      : css`
          ${pulse} 2s infinite
        `};
`;

const StyledFontAwesomeIcon = styled(FontAwesomeIcon)`
  color: #ffffff;
  font-size: ${({ repository }) =>
    repository === "frontMulti" ? "18px" : "15px"};
`;

const ECG_ROW_GAP = 12;
const DEFAULT_VIEWPORT_HEIGHT = 900;
const SAMPLE_FREQUENCY_HZ = 300;

const EcgPanel = ({
  isPin,
  setIsPin,
  recordData,
  startRecord,
  stage,
  mvScale,
  msScale,
  helpersRef,
  height = 161,
  fullNameUser = "Doctor1",
  commentsDB,
  secondcheck,
  setSecondcheck,
  continuesecondtocomments,
  setContinuesecondtocomments,
  addComment,
  lastMarginRightDB = 1706,
  repository,
  isOpenFromModal = false,
}) => {
  const [showderivates, setShowderivates] = useState(false);
  const [comments, setComments] = useState([]);
  const [pinnedDerivation, setPinnedDerivation] = useState();
  const [left, setLeft] = useState(0);
  const [right, setRight] = useState(0);
  const [panelWidth, setPanelWidth] = useState(0);
  const [viewportHeight, setViewportHeight] = useState(() =>
    typeof window !== "undefined"
      ? window.innerHeight
      : DEFAULT_VIEWPORT_HEIGHT,
  );

  const containerForModal = useRef();
  const stopMoveRef = useRef(false);
  const panelMeasureRef = useRef(null);

  const normalizedLastMarginRight = Math.max(lastMarginRightDB || 0, 1);
  const totalSamples = useMemo(() => {
    return (
      Object.values(recordData || {}).find(
        (dataset) => Array.isArray(dataset) && dataset.length
      )?.length || 0
    );
  }, [recordData]);
  const totalSeconds = useMemo(
    () => (totalSamples > 0 ? totalSamples / SAMPLE_FREQUENCY_HZ : 0),
    [totalSamples],
  );
  const sampleDistance = useMemo(
    () => distanceBetweenPoints(msScale),
    [msScale],
  );

  const {
    play,
    stop,
    next,
    initialize,
    finalize,
    drawViewportFragment,
    drawNavigatorMiniature,
    reset,
  } = useDrawDerivations(
    {
      color: "#B163FF",
      mvScale,
      msScale,
      totalTrackWidth: normalizedLastMarginRight,
    },
    () => {},
    recordData,
    setShowderivates,
  );

  useLayoutEffect(() => {
    if (!panelMeasureRef.current) {
      return undefined;
    }

    const element = panelMeasureRef.current;
    const updateLayoutMetrics = () => {
      setPanelWidth(Math.floor(element.getBoundingClientRect().width));
      if (typeof window !== "undefined") {
        setViewportHeight(window.innerHeight);
      }
    };

    updateLayoutMetrics();

    if (typeof ResizeObserver !== "undefined") {
      const observer = new ResizeObserver(() => updateLayoutMetrics());
      observer.observe(element);
      window.addEventListener("resize", updateLayoutMetrics);
      return () => {
        observer.disconnect();
        window.removeEventListener("resize", updateLayoutMetrics);
      };
    }

    window.addEventListener("resize", updateLayoutMetrics);
    return () => window.removeEventListener("resize", updateLayoutMetrics);
  }, []);

  const metrics = useMemo(() => {
    const resolvedWidth = panelWidth || 720;
    const compact = resolvedWidth < 760;
    const shellGap = resolvedWidth < 480 ? 12 : 20;
    const contentWidth = Math.max(
      compact ? resolvedWidth : resolvedWidth - 64 - shellGap,
      300,
    );
    const labelWidth = resolvedWidth < 480 ? 58 : 68;
    const leadRailWidth = resolvedWidth < 480 ? 110 : 126;
    const navigatorRailWidth = resolvedWidth < 480 ? 86 : 96;
    const mainPlotWidth = Math.max(contentWidth - leadRailWidth, 220);
    const navigatorPlotWidth = Math.max(contentWidth - navigatorRailWidth, 220);
    const visibleSamples = Math.max(
      Math.floor(mainPlotWidth / Math.max(sampleDistance, 0.1)),
      2,
    );
    const unitsPerSample =
      totalSamples > 1
        ? normalizedLastMarginRight / Math.max(totalSamples - 1, 1)
        : normalizedLastMarginRight;
    const visibleTrackWidth =
      totalSamples > 1
        ? Math.min(
            // Stay strictly below the total so maxTrackLeft > 0 and the
            // viewport window can always be dragged.
            normalizedLastMarginRight - unitsPerSample,
            Math.max(visibleSamples * unitsPerSample, unitsPerSample * 2),
          )
        : normalizedLastMarginRight;

    return {
      compact,
      shellGap,
      contentWidth,
      labelWidth,
      leadRailWidth,
      navigatorRailWidth,
      mainPlotWidth,
      navigatorPlotWidth,
      visibleTrackWidth,
      cardPadding: resolvedWidth < 480 ? 12 : 18,
    };
  }, [normalizedLastMarginRight, panelWidth, sampleDistance, totalSamples]);

  const {
    compact,
    contentWidth,
    labelWidth,
    leadRailWidth,
    navigatorRailWidth,
    navigatorPlotWidth,
    visibleTrackWidth,
    cardPadding,
  } = metrics;

  const derivations = useMemo(
    () => [
      { derivation: "di", label: "DI" },
      { derivation: "dii", label: "DII" },
      { derivation: "diii", label: "DIII" },
      { derivation: "v1" },
      { derivation: "v2" },
      { derivation: "v3" },
      { derivation: "v4" },
      { derivation: "v5" },
      { derivation: "v6" },
      { derivation: "aVR" },
      { derivation: "aVF" },
      { derivation: "aVL" },
    ],
    [],
  );

  const { derivationHeight, scrollAreaHeight, pinnedHeight } = useMemo(() => {
    const reservedHeight = isOpenFromModal ? 360 : 300;
    const rowStride = height + ECG_ROW_GAP;
    const minimumScrollableHeight = height;
    const availableScrollableHeight = Math.max(
      viewportHeight - reservedHeight,
      minimumScrollableHeight,
    );
    const totalScrollableHeight = derivations.length * rowStride - ECG_ROW_GAP;

    return {
      derivationHeight: height,
      scrollAreaHeight: Math.min(
        availableScrollableHeight,
        totalScrollableHeight,
      ),
      pinnedHeight: Math.max(220, Math.round(height * 1.5)),
    };
  }, [derivations.length, height, isOpenFromModal, viewportHeight]);

  const navigatorHeight = 100;

  const clampViewportRange = useCallback(
    (nextLeft, nextRight = nextLeft + visibleTrackWidth) => {
      const resolvedWidth = Math.min(
        Math.max(Math.round(nextRight - nextLeft), 1),
        Math.max(Math.round(visibleTrackWidth || 1), 1),
        normalizedLastMarginRight,
      );
      const maxLeft = Math.max(normalizedLastMarginRight - resolvedWidth, 0);
      const clampedLeft = Math.min(Math.max(Math.round(nextLeft || 0), 0), maxLeft);

      return {
        left: clampedLeft,
        right: Math.min(clampedLeft + resolvedWidth, normalizedLastMarginRight),
      };
    },
    [normalizedLastMarginRight, visibleTrackWidth],
  );

  const handleViewportChange = useCallback(
    (nextLeft, nextRight) => {
      const nextRange = clampViewportRange(nextLeft, nextRight);
      setLeft(nextRange.left);
      setRight(nextRange.right);
    },
    [clampViewportRange],
  );

  let label;
  switch (pinnedDerivation) {
    case "di":
      label = "DI";
      break;
    case "dii":
      label = "DII";
      break;
    case "diii":
      label = "DIII";
      break;
    default:
      label = pinnedDerivation;
      break;
  }

  useEffect(() => {
    if (!helpersRef) {
      return;
    }

    helpersRef.current = {
      play,
      stop,
      next,
      initialize,
      finalize,
      drawViewportFragment,
      reset,
    };
  }, [
    drawViewportFragment,
    finalize,
    helpersRef,
    initialize,
    next,
    play,
    reset,
    stop,
  ]);

  useEffect(() => {
    if (!recordData || !visibleTrackWidth) {
      return;
    }

    setShowderivates(false);
    setPinnedDerivation(undefined);
    setIsPin(false);

    const initialRange = clampViewportRange(0, visibleTrackWidth);
    setLeft(initialRange.left);
    setRight(initialRange.right);

    const frame = requestAnimationFrame(() => {
      drawNavigatorMiniature(recordData);
      setShowderivates(true);
    });

    return () => cancelAnimationFrame(frame);
  }, [
    clampViewportRange,
    drawNavigatorMiniature,
    recordData,
    setIsPin,
    visibleTrackWidth,
  ]);

  useEffect(() => {
    if (!recordData || !showderivates) {
      return;
    }

    const frame = requestAnimationFrame(() => {
      drawViewportFragment(left, right, recordData, stopMoveRef);
    });

    return () => cancelAnimationFrame(frame);
  }, [
    drawViewportFragment,
    isPin,
    left,
    pinnedDerivation,
    recordData,
    right,
    showderivates,
  ]);

  useEffect(() => {
    if (!recordData || !navigatorPlotWidth) {
      return;
    }

    const frame = requestAnimationFrame(() => {
      drawNavigatorMiniature(recordData);
    });

    return () => cancelAnimationFrame(frame);
  }, [drawNavigatorMiniature, navigatorPlotWidth, recordData]);

  useEffect(() => {
    try {
      if (!commentsDB || visibleTrackWidth <= 0) {
        setComments([]);
        return;
      }

      const commentsRespExtend = commentsDB.map((comment) => {
        let leftPixels;
        let rightPixels;
        const commentLeft = parseInt(comment.from, 10);
        const commentRight = parseInt(comment.to, 10);

        if (comment.source !== "ecgplayer") {
          const { leftPixelsPlayer, rightPixelsPlayer } =
            getPixelsFromViewerToPlayer(
              commentLeft,
              commentRight,
              204.4,
              visibleTrackWidth,
            );
          leftPixels = leftPixelsPlayer;
          rightPixels = rightPixelsPlayer;
        } else {
          leftPixels = Number.isFinite(commentLeft) ? commentLeft : 0;
          rightPixels =
            Number.isFinite(commentRight) && commentRight > leftPixels
              ? commentRight
              : leftPixels + visibleTrackWidth;
        }

        leftPixels = Math.max(0, Math.min(leftPixels, normalizedLastMarginRight));
        rightPixels = Math.max(
          leftPixels + 1,
          Math.min(rightPixels, normalizedLastMarginRight),
        );

        const { leftSeconds, rightSeconds } = getSecondsFromPixels(
          leftPixels,
          rightPixels,
          normalizedLastMarginRight,
          Math.max(totalSeconds, 1),
        );

        return {
          ...comment,
          from: leftPixels,
          to: rightPixels,
          fromSeconds: leftSeconds,
          toSeconds: rightSeconds,
        };
      });

      setComments(commentsRespExtend);
    } catch (error) {
      console.log("error_db", JSON.stringify(error));
    }
  }, [
    commentsDB,
    normalizedLastMarginRight,
    totalSeconds,
    visibleTrackWidth,
  ]);

  const handlePin = useCallback(
    (event, derivation) => {
      event.preventDefault();
      if (isPin && pinnedDerivation === derivation) {
        setIsPin(false);
        setPinnedDerivation(undefined);
        return;
      }

      setIsPin(true);
      setPinnedDerivation(derivation);
    },
    [isPin, pinnedDerivation, setIsPin],
  );

  const {
    dragIndicators,
    loading,
    viewlistcomments,
    handleListcomments,
    handleFocusMarginsEcg,
    handleDragIndicators,
    showModalComments,
    setShowModalComments,
  } = useComments({
    currentRange: { left, right },
    viewportWidth: visibleTrackWidth,
    totalWidth: normalizedLastMarginRight,
    totalSeconds,
    onFocusRange: handleViewportChange,
  });

  const finishOverlayActive = !secondcheck && !continuesecondtocomments;

  return (
    <I18nextProvider i18n={i18next}>
      <PanelRoot ref={panelMeasureRef}>
        <PanelShell $compact={compact} $gap={metrics.shellGap}>
          <ControlRail $compact={compact}>
            <ControlButtonFrame>
              <ECGButton
                type="button"
                onClick={() => {
                  handleListcomments();
                }}
                secondcheck={secondcheck}
                continuesecondtocomments={continuesecondtocomments}
                repository={repository}
              >
                <StyledFontAwesomeIcon
                  icon={faCommentAlt}
                  repository={repository}
                />
              </ECGButton>
            </ControlButtonFrame>
          </ControlRail>

          <ContentColumn ref={containerForModal} id="ecg-panel-modal-root">
            <ECGCard $padding={cardPadding}>
              {finishOverlayActive && (
                <FinishSecondEcgComponent
                  setContinuesecondtocomments={setContinuesecondtocomments}
                  setSecondcheck={setSecondcheck}
                  repository={repository}
                />
              )}

              <PlayerSurface $muted={finishOverlayActive}>
                {!isPin ? (
                  <ECGScrollArea
                    $height={scrollAreaHeight}
                    $rowGap={ECG_ROW_GAP}
                  >
                    {derivations.map((d) => (
                      <ECG
                        isPin={isPin}
                        handlePin={handlePin}
                        key={d.derivation}
                        derivation={d.derivation}
                        label={d?.label}
                        height={derivationHeight}
                        width={contentWidth}
                        repository={repository}
                        labelWidth={labelWidth}
                        railWidth={leadRailWidth}
                      />
                    ))}
                  </ECGScrollArea>
                ) : (
                  <PinnedWrapper>
                    <ECG
                      isPin={isPin}
                      handlePin={handlePin}
                      key={pinnedDerivation}
                      derivation={pinnedDerivation}
                      label={label}
                      height={pinnedHeight}
                      width={contentWidth}
                      repository={repository}
                      labelWidth={labelWidth}
                      railWidth={leadRailWidth}
                    />
                  </PinnedWrapper>
                )}

                <NavigatorSection>
                  <EcgNavigator
                    height={navigatorHeight}
                    width={contentWidth}
                    railWidth={navigatorRailWidth}
                    totalWidth={normalizedLastMarginRight}
                    viewportWidth={visibleTrackWidth}
                    currentLeft={left}
                    onViewportChange={handleViewportChange}
                    repository={repository}
                    labelWidth={labelWidth}
                  />
                </NavigatorSection>
              </PlayerSurface>

              {!showderivates && (
                <SkeletonOverlay $padding={cardPadding}>
                  <SkeletonContainer
                    repository={repository}
                    isOpenFromModal={isOpenFromModal}
                    width={contentWidth}
                    rowHeight={derivationHeight}
                  />
                </SkeletonOverlay>
              )}
            </ECGCard>

            <ActionRow>
              {!continuesecondtocomments ? (
                <ButtonContinue
                  repository={repository}
                  setContinuesecondtocomments={setContinuesecondtocomments}
                />
              ) : (
                <ButtonAdd
                  isPin={isPin}
                  repository={repository}
                  handleDragIndicators={handleDragIndicators}
                />
              )}
            </ActionRow>

            <AddCommentDialog
              loading={loading}
              viewlistcomments={viewlistcomments}
              open={showModalComments}
              handleClose={() => {
                setShowModalComments(false);
              }}
              dragIndicators={dragIndicators}
              comments={comments}
              setComments={setComments}
              handleFocusMarginsEcg={handleFocusMarginsEcg}
              containerForModal={containerForModal}
              fullNameUser={fullNameUser}
              left={left}
              right={right}
              addComment={addComment}
              repository={repository}
              widthOfEcgPanel={contentWidth}
              timelineWidth={normalizedLastMarginRight}
              totalSeconds={totalSeconds}
            />
          </ContentColumn>
        </PanelShell>
      </PanelRoot>
    </I18nextProvider>
  );
};

export default EcgPanel;
