import React, { useState, useEffect, useRef, useMemo, useLayoutEffect, useCallback } from "react";
import axios from "axios";
import { observer } from "mobx-react-lite";
import { useGeolocationStore } from "../../stores";
import ContentAPI from "../../api/content/content.api";
import { getMediaType } from "../../utils/getMediaType";
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer";
import { ThreeView } from "../widgets/ThreeView";
import {
  MinusIcon,
  PlusIcon,
  SizeIcon,
  SizeOpenIcon,
} from "../widgets/ThreeViewIcons";
import { ThreeViewErrorBoundary } from "../ThreeViewErrorBoundary";
import { apiStore } from "../../api/ApiStore/store";
import { ReactMarkdownComponent } from "../ReactMarkdown";
import { TouchableLayout } from "../TouchableLayout";
import rotate3DIcon from "../../assets/icons/three-view-rotate.svg";
import zoom3DIcon from "../../assets/icons/three-view-zoom.svg";
import pan3DIcon from "../../assets/icons/three-view-pan.svg";
import subtractHomeIcon from "../../assets/icons/subtract-home.svg";

const Watermark = ({ path }) => {
  if (!path) return null;
  return <img className="watermark" src={path} alt="watermark" />;
};

const SightFrame = observer(({ media, sight_id, sight_name }) => {
  const store = useGeolocationStore();
  const { selectedLanguageRight } = store;

  const [articleSections, setArticleSections] = useState(null);
  const [isLoadingContent, setIsLoadingContent] = useState(true);
  const [contentError, setContentError] = useState(null);
  const [selectedSection, setSelectedSection] = useState(0);
  const [modelAspectRatio, setModelAspectRatio] = useState(null);
  const [isVisible, setIsVisible] = useState(false);
  const [sightData, setSightData] = useState(null);
  const [mediaData, setMediaData] = useState({});
  const [isFullscreen3D, setIsFullscreen3D] = useState(false);
  const [fullscreenFileUrl, setFullscreenFileUrl] = useState("");
  const [threeViewResetKey, setThreeViewResetKey] = useState(0);
  const threeViewControlRef = useRef(null);
  const mediaCache = useRef({});
  const idleTimerRef = useRef(null);

  const textWrapperRef = useRef(null);
  const menuRef = useRef(null);
  const [menuNeedsScroll, setMenuNeedsScroll] = useState(false);
  const [canScrollLeft, setCanScrollLeft] = useState(false);
  const [canScrollRight, setCanScrollRight] = useState(false);

  const updateScrollState = useCallback(() => {
    const menu = menuRef.current;
    if (!menu) return;
    setCanScrollLeft(menu.scrollLeft > 2);
    setCanScrollRight(menu.scrollLeft + menu.clientWidth < menu.scrollWidth - 2);
  }, []);

  useEffect(() => {
    const menu = menuRef.current;
    if (!menu || !menuNeedsScroll) {
      setCanScrollLeft(false);
      setCanScrollRight(false);
      return;
    }
    updateScrollState();
    menu.addEventListener('scroll', updateScrollState);
    return () => menu.removeEventListener('scroll', updateScrollState);
  }, [menuNeedsScroll, updateScrollState]);

  useLayoutEffect(() => {
    const menu = menuRef.current;
    if (!menu) return;
    const children = Array.from(menu.querySelectorAll('.sight-frame-menu-point'));
    if (children.length < 2) {
      setMenuNeedsScroll(false);
      return;
    }
    const style = getComputedStyle(menu);
    const availableWidth = menu.clientWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
    const totalChildrenWidth = children.reduce((sum, el) => sum + el.offsetWidth, 0);
    const evenGap = (availableWidth - totalChildrenWidth) / (children.length + 1);
    setMenuNeedsScroll(evenGap < 10);
  }, [articleSections, selectedSection]);

  // Автозакрытие fullscreen 3D при бездействии (60 сек)
  useEffect(() => {
    if (!isFullscreen3D) {
      if (idleTimerRef.current) {
        clearInterval(idleTimerRef.current);
        idleTimerRef.current = null;
      }
      return;
    }

    let idleSeconds = 0;

    const checkIdle = () => {
      idleSeconds += 1;
      if (idleSeconds >= 60) {
        setIsFullscreen3D(false);
      }
    };

    idleTimerRef.current = setInterval(checkIdle, 1000);

    const resetIdle = () => {
      idleSeconds = 0;
    };

    const events = [
      "mousedown",
      "mousemove",
      "keypress",
      "scroll",
      "touchstart",
      "click",
    ];
    events.forEach((event) => {
      window.addEventListener(event, resetIdle, { passive: true });
    });

    return () => {
      if (idleTimerRef.current) {
        clearInterval(idleTimerRef.current);
        idleTimerRef.current = null;
      }
      events.forEach((event) => {
        window.removeEventListener(event, resetIdle);
      });
    };
  }, [isFullscreen3D]);

  const {
    routeSights,
    routeSightsEn,
    routeSightsZh,
    sightArticles,
    sightArticlesEn,
    sightArticlesZh,
    sightArticlesIds,
  } = apiStore;

  const isStringUuid = (id) =>
    typeof id === "string" &&
    id.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i);

  const fetchMediaForSection = async (sectionId, signal) => {
    if (!sectionId || sectionId === "intro-title") return null;

    try {
      const usePreviewApi = isStringUuid(sectionId);
      const fetchedMediaObj = usePreviewApi
        ? await ContentAPI.getMediaPreview(sectionId, "ru", signal)
        : await ContentAPI.getMedia(sectionId, "ru", signal);

      return {
        path: fetchedMediaObj.path,
        type: getMediaType(fetchedMediaObj.type),
      };
    } catch (err) {
      if (axios.isCancel(err) || err.name === "AbortError") return null;
      console.error(`Failed to fetch media for section ${sectionId}:`, err);
      return null;
    }
  };

  useEffect(() => {
    const controller = new AbortController();
    const { signal } = controller;

    setIsLoadingContent(true);
    setContentError(null);
    setModelAspectRatio(null);
    setIsVisible(false);
    setMediaData({});

    if (!sight_id) {
      setContentError("Не указан ID статьи.");
      setIsLoadingContent(false);
      return () => controller.abort();
    }

    const fetchContent = async () => {
      try {
        const sight =
          selectedLanguageRight === "ru"
            ? routeSights.find((sight) => sight.id === sight_id)
            : selectedLanguageRight === "en"
              ? routeSightsEn.find((sight) => sight.id === sight_id)
              : routeSightsZh.find((sight) => sight.id === sight_id);

        if (!sight) {
          setContentError("Достопримечательность не найдена.");
          setIsLoadingContent(false);
          return;
        }

        const rightArticleData = sightArticlesIds.get(sight_id);

        if (!rightArticleData) {
          setContentError("Данные о статьях не найдены.");
          setIsLoadingContent(false);
          return;
        }

        const rightArticles = rightArticleData.map((articleId) => {
          const article =
            selectedLanguageRight === "ru"
              ? sightArticles.get(articleId.toString() + "_ru")
              : selectedLanguageRight === "en"
                ? sightArticlesEn.get(articleId.toString() + "_en")
                : sightArticlesZh.get(articleId.toString() + "_zh");

          if (!article) {
            console.warn(
              `Article not found for ID: ${articleId} in language: ${selectedLanguageRight}`,
            );
            return {
              id: articleId,
              heading: "Статья не найдена",
              body: "Содержание статьи недоступно.",
            };
          }

          const processBodyText = (text) => {
            if (!text) return text;

            const namePattern =
              /[А-Яа-яA-Za-z0-9]\.[А-Яа-яA-Za-z0-9]\.[А-Яа-яA-Za-z0-9]+|[А-Яа-яA-Za-z0-9]\. [А-Яа-яA-Za-z0-9]\. [А-Яа-яA-Za-z0-9]+/g;

            const hasNamePattern = namePattern.test(text);

            if (hasNamePattern) {
              return text.replace(/\n/g, " ");
            }

            return text;
          };

          return {
            id: articleId,
            heading: article.heading,
            body: processBodyText(article.body),
          };
        });

        if (signal.aborted) return;

        setSightData(sight);
        const introSection = {
          id: media?.id || "intro-title",
          heading:
            sight?.short_name ||
            sight?.name ||
            sight_name ||
            "Название достопримечательности",
          body: "",
        };
        const allSections = [introSection, ...rightArticles];
        setArticleSections(allSections);

        const cacheKey = `${sight_id}_${selectedLanguageRight}`;
        if (mediaCache.current[cacheKey]) {
          setMediaData(mediaCache.current[cacheKey]);
          setIsLoadingContent(false);
          setIsVisible(true);
          return;
        }

        const mediaSections = allSections.filter(
          (s) => s.id && s.id !== "intro-title",
        );
        const results = await Promise.all(
          mediaSections.map((s) => fetchMediaForSection(s.id, signal)),
        );

        if (signal.aborted) return;

        const newMediaData = {};
        mediaSections.forEach((s, i) => {
          if (results[i]) newMediaData[s.id] = results[i];
        });

        mediaCache.current[cacheKey] = newMediaData;
        setMediaData(newMediaData);
        setIsLoadingContent(false);
        setIsVisible(true);
      } catch (err) {
        if (axios.isCancel(err) || signal.aborted) return;
        console.error("Error fetching content:", err);
        setContentError("Не удалось загрузить информацию.");
        setIsLoadingContent(false);
      }
    };

    fetchContent();
    return () => controller.abort();
  }, [sight_id, selectedLanguageRight, media]);

  useEffect(() => {
    setSelectedSection(0);
  }, [sight_id]);

  const currentSection = articleSections?.[selectedSection] ?? null;

  const renderCurrentMedia = () => {
    if (!articleSections || Object.keys(mediaData).length === 0) {
      return (
        <div className="sight-frame-image-placeholder">
          {isLoadingContent ? "Загрузка медиа..." : "Нет медиа для отображения"}
        </div>
      );
    }

    const section = articleSections[selectedSection];
    if (!section) return null;

    const sectionId = section.id?.toString();
    const currentMediaData = mediaData[sectionId];
    if (!currentMediaData) return null;

    const className = "sight-frame-media-item visible";

    try {
      switch (currentMediaData.type) {
        case "image":
          return (
            <img
              key={sectionId}
              src={currentMediaData.path}
              alt=""
              className={className}
              onError={(e) => {
                console.warn(`Failed to load image: ${currentMediaData.path}`);
                e.target.style.display = "none";
              }}
            />
          );
        case "video":
          return (
            <video
              key={sectionId}
              muted
              autoPlay
              loop
              playsInline
              className={className}
              onError={(e) => {
                console.warn(`Failed to load video: ${currentMediaData.path}`);
                e.target.style.display = "none";
              }}
            >
              <source src={currentMediaData.path} type="video/mp4" />
            </video>
          );
        case "panorama":
          return (
            <div
              key={sectionId}
              className={`${className} panorama-container`}
              style={{ isolation: "isolate" }}
            >
              <ReactPhotoSphereViewer
                src={currentMediaData.path}
                width={"100%"}
                height={"100%"}
                showFullscreenButton={false}
                showZoomButton={false}
                showPhotoDome={false}
              />
            </div>
          );
        case "3d":
          return (
            <div
              key={sectionId}
              className={className}
              style={{ position: "relative" }}
            >
              <ThreeViewErrorBoundary
                resetKey={`${currentMediaData.id}-${threeViewResetKey}`}
                onReset={() => {
                  setThreeViewResetKey((prev) => prev + 1);
                }}
              >
                <ThreeView
                  key={`widget-${sectionId}-${isFullscreen3D}-${threeViewResetKey}`}
                  fileUrl={currentMediaData.path}
                  width={"100%"}
                  height={"100%"}
                  onAspectRatioCalculated={setModelAspectRatio}
                  controlRef={threeViewControlRef}
                />
              </ThreeViewErrorBoundary>
              <div className="three-d-controls-bar">
                <button
                  type="button"
                  className="three-d-control-btn"
                  onPointerUp={() => threeViewControlRef.current?.zoomOut?.()}
                >
                  <MinusIcon />
                </button>
                <button
                  type="button"
                  className="three-d-control-btn"
                  onPointerUp={() => threeViewControlRef.current?.zoomIn?.()}
                >
                  <PlusIcon />
                </button>
                <button
                  type="button"
                  className="three-d-control-btn"
                  onPointerUp={() => {
                    if (isFullscreen3D) {
                      setIsFullscreen3D(false);
                    } else {
                      setFullscreenFileUrl(currentMediaData.path);
                      setIsFullscreen3D(true);
                    }
                  }}
                >
                  {isFullscreen3D ? <SizeIcon /> : <SizeOpenIcon />}
                </button>
              </div>
              <button
                className={"fullscreen-3d-button"}
                aria-hidden="true"
              >
                <svg
                  width="44"
                  height="48"
                  viewBox="0 0 44 48"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M42.69 11.3375L22.79 0.2475C22.2 -0.0825 21.48 -0.0825 20.89 0.2475L1 11.3475C0.38 11.6875 0 12.3475 0 13.0475V34.9875C0 35.6975 0.38 36.3475 1 36.6875L20.9 47.7475C21.49 48.0775 22.2 48.0775 22.79 47.7475L42.69 36.6775C43.31 36.3375 43.69 35.6775 43.69 34.9775V13.0375C43.69 12.3375 43.31 11.6775 42.69 11.3375ZM19.64 40.5975C19.64 41.2375 18.96 41.6375 18.4 41.3275L5.41 34.1075C4.78 33.7575 4.4 33.0975 4.4 32.3875V18.3675C4.4 17.7275 5.08 17.3275 5.64 17.6375L18.63 24.8575C19.26 25.2075 19.64 25.8675 19.64 26.5775V40.5975ZM20.88 21.0675L8.03 13.9275C7.46 13.6075 7.46 12.7875 8.03 12.4675L20.88 5.2975C21.47 4.9675 22.2 4.9675 22.8 5.2975L35.65 12.4575C36.22 12.7775 36.22 13.5975 35.65 13.9175L22.8 21.0675C22.21 21.3975 21.48 21.3975 20.89 21.0675H20.88ZM39.29 32.3875C39.29 33.1075 38.9 33.7575 38.28 34.1075L25.29 41.3275C24.73 41.6375 24.05 41.2375 24.05 40.5975V26.5775C24.05 25.8575 24.44 25.2075 25.06 24.8575L38.05 17.6375C38.61 17.3275 39.29 17.7275 39.29 18.3675V32.3875Z"
                    fill="white"
                  />
                </svg>
              </button>
              {isFullscreen3D && (
                <div
                  style={{
                    position: "absolute",
                    top: 94,
                    right: 10,
                    zIndex: 10,
                    pointerEvents: "none",
                  }}
                >
                  <div
                    className="cluster-sights-list"
                    style={{
                      background: `linear-gradient(to bottom right, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 100%), rgba(var(--carrier-right-rgb, 0, 111, 58), 0.4)`,
                      backdropFilter: "blur(10px)",
                      borderRadius: "8px",
                      width: 200,
                      boxShadow:
                        "0 0 0 1px rgba(255, 255, 255, 0.3) inset, 4px 4px 12px 0 rgba(255, 255, 255, 0.12) inset",
                      display: "flex",
                      flexDirection: "column",
                      padding: "8px 13px",
                    }}
                  >
                    {[
                      {
                        label: "Вращать",
                        icon: (
                          <img
                            src={rotate3DIcon}
                            alt=""
                            width="14"
                            height="14"
                          />
                        ),
                      },
                      {
                        label: "Приблизить / Отдалить",
                        icon: (
                          <img src={zoom3DIcon} alt="" width="14" height="14" />
                        ),
                      },
                      {
                        label: "Переместить",
                        icon: (
                          <img src={pan3DIcon} alt="" width="14" height="14" />
                        ),
                      },
                    ].map((item, index, arr) => (
                      <div
                        key={index}
                        style={{
                          display: "flex",
                          alignItems: "center",
                          height: "30px",
                          userSelect: "none",
                          touchAction: "none",
                          padding: "0 4px",
                          borderBottom:
                            index < arr.length - 1
                              ? "1px solid rgba(255, 255, 255, 0.1)"
                              : "none",
                          transition: "background-color 0.2s",
                        }}
                      >
                        <span
                          style={{
                            display: "block",
                            marginRight: "8px",
                            flexShrink: 0,
                            lineHeight: 0,
                          }}
                        >
                          {item.icon}
                        </span>
                        <span
                          style={{
                            color: "white",
                            fontSize: "12px",
                            lineHeight: "1.5",
                            fontWeight: "400",
                            overflow: "hidden",
                            textOverflow: "ellipsis",
                            whiteSpace: "nowrap",
                            flex: 1,
                          }}
                        >
                          {item.label}
                        </span>
                      </div>
                    ))}
                  </div>
                </div>
              )}
            </div>
          );
        default:
          return (
            <div key={sectionId} className={className}>
              <div className="sight-frame-image-placeholder">
                Неподдерживаемый тип медиа: {currentMediaData.type}
              </div>
            </div>
          );
      }
    } catch (error) {
      console.error(`Error rendering media ${sectionId}:`, error);
      return (
        <div key={sectionId} className={className}>
          <div className="sight-frame-image-placeholder error-message">
            Ошибка отображения медиа
          </div>
        </div>
      );
    }
  };

  const isCurrentMedia3D =
    currentSection && mediaData[currentSection.id]?.type === "3d";

  const getMediaStackStyle = () => {
    if (isCurrentMedia3D && isFullscreen3D) {
      const fullHeight = window.innerHeight * 0.8;

      const width = modelAspectRatio
        ? fullHeight * modelAspectRatio
        : fullHeight * 1.3;

      const finalWidth = Math.max(width, 550);
      const containerWidth = 550;
      const extraWidth = Math.max(0, finalWidth - containerWidth);

      return {
        height: `${fullHeight}px`,
        width: `${finalWidth}px`,
        maxWidth: "100vw",
        overflow: "visible",
        marginLeft: `-${extraWidth}px`,
        marginTop: `-2px`,
      };
    }
    if (isCurrentMedia3D) {
      if (modelAspectRatio) {
        const width = 400;
        const height = Math.min(
          width / modelAspectRatio,
          window.innerHeight * 0.7,
        );
        return { height: `${height}px` };
      }
      return { height: "500px" };
    }
    return {};
  };

  const processedSightName = useMemo(() => {
    if (!sight_name) return sight_name;

    // Handle \n line breaks (только в правом виджете)
    if (sight_name.includes("\n")) {
      return sight_name.split("\n").map((line, i) => (
        <React.Fragment key={i}>
          {i > 0 && <br />}
          {line}
        </React.Fragment>
      ));
    }

    const namePattern =
      /([А-Яа-яA-Za-z0-9]\. [А-Яа-яA-Za-z0-9]\. [А-Яа-яA-Za-z0-9]+)/g;

    const parts = sight_name.split(namePattern);

    if (parts.length > 1) {
      return parts.map((part, index) => {
        const initialsPattern =
          /^[А-Яа-яA-Za-z0-9]\. [А-Яа-яA-Za-z0-9]\. [А-Яа-яA-Za-z0-9]+$/;
        if (initialsPattern.test(part)) {
          return (
            <React.Fragment key={index}>
              <br />
              {part}
            </React.Fragment>
          );
        }
        return <React.Fragment key={index}>{part}</React.Fragment>;
      });
    }

    return sight_name;
  }, [sight_name]);

  const titleLineHeight = useMemo(() => {
    if (!sight_name) return "120%";
    const textLength = sight_name.replace(/\n/g, "").length;
    const calculatedLineHeight = Math.max(
      100,
      Math.min(120, 120 - (textLength / 10) * 1),
    );
    return `${calculatedLineHeight}%`;
  }, [sight_name]);

  return (
    <div
      className={`sight-frame ${isVisible ? "is-visible" : ""} ${
        isFullscreen3D && isCurrentMedia3D ? "three-d-fullscreen" : ""
      }`}
    >
      {sightData?.watermark_lu && !isFullscreen3D && (
        <Watermark path={ContentAPI.getMediaPath(sightData.watermark_lu)} />
      )}
      <div
        className={`sight-frame-media-stack ${
          isCurrentMedia3D ? "three-d-view" : ""
        }`}
        style={getMediaStackStyle()}
      >
        {contentError ? (
          <div className="sight-frame-image-placeholder error-message">
            {contentError}
          </div>
        ) : isLoadingContent || !articleSections ? (
          <div className="sight-frame-image-placeholder">
            Загрузка контента...
          </div>
        ) : (
          renderCurrentMedia()
        )}
      </div>
      <div className="sight-frame-content">
        {contentError ? (
          <p className="error-message">{contentError}</p>
        ) : !currentSection ? (
          <p>Информация отсутствует.</p>
        ) : (
          <>
            {!isFullscreen3D && (
              <div
                className={`sight-frame-title ${
                  selectedSection === 0 ? "intro-title" : ""
                }`}
                style={{ lineHeight: titleLineHeight }}
              >
                <p
                  style={{
                    whiteSpace: "normal",
                    wordBreak: "break-word",
                    overflowWrap: "break-word",
                  }}
                >
                  {selectedSection === 0
                    ? processedSightName
                    : sightData?.short_name || sight_name}
                </p>
              </div>
            )}
            {selectedSection !== 0 && (
              <TouchableLayout
                className="sight-frame-text-wrapper"
                ref={textWrapperRef}
                maxHeight="calc(80vh - 354px)"
              >
                <div className="sight-frame-text">
                  <ReactMarkdownComponent value={currentSection.body} />
                </div>
              </TouchableLayout>
            )}
          </>
        )}
      </div>
      <div className="sight-frame-menu-wrapper">
        <div className="sight-frame-menu-fade left" style={{ opacity: canScrollLeft ? 1 : 0 }} />
        <div className="sight-frame-menu-fade right" style={{ opacity: canScrollRight ? 1 : 0 }} />
      <div
        className="sight-frame-menu"
        ref={menuRef}
        style={menuNeedsScroll ? { justifyContent: 'space-between' } : undefined}
      >
        <div
          style={{
            position: "absolute",
            left: "10px",
            marginTop: "-4.5px",
            zIndex: 1,
            paddingLeft: "15px",
            paddingRight: "7.5px",
            paddingTop: "4.5px",
            paddingBottom: "4.5px",
            cursor: "pointer",
            opacity: selectedSection !== 0 ? 1 : 0,
            transform: selectedSection !== 0 ? "scale(1)" : "scale(0.5)",
            transition: "opacity 0.3s ease, transform 0.3s ease",
            pointerEvents: selectedSection !== 0 ? "auto" : "none",
          }}
          onPointerUp={() => {
            setSelectedSection(0);
            setIsFullscreen3D(false);
          }}
        >
          <img
            src={subtractHomeIcon}
            alt=""
            width="24"
            height="21"
            style={{ display: "block" }}
          />
        </div>
        {contentError ? (
          <p className="error-message">{contentError}</p>
        ) : (
          articleSections &&
          articleSections.length > 1 &&
          articleSections.slice(1).map((section, index) => (
            <div
              onPointerUp={() => {
                setSelectedSection(index + 1);
                setIsFullscreen3D(false);
              }}
              key={section.id || section.heading || index}
              className={`sight-frame-menu-point ${
                index + 1 === selectedSection ? "active" : ""
              }`}
              role="button"
              tabIndex="0"
            >
              {section.heading}
            </div>
          ))
        )}
      </div>
      </div>
    </div>
  );
});

export default SightFrame;
