import React, { useState, useEffect, useRef, useCallback } from "react";
import "./ImageGallery.css";
import moment from "moment";
import { useSelector } from "react-redux";
import { useModal } from "./ModalContext";
import ImagePop from "./ImagePop";
import Avatar from "../../components/common/Avatar";
import DateRangePicker from "../../components/common/DateRangePicker";
import eventBus from "../../services/eventBus";
import Breadcrumb from "../../components/common/Breadcrumb";
import { formatUTCToLocalTime } from "../../utils/dateUtils";
import useImageGallery from "../../hooks/useImageGallery";

const SCROLL_THRESHOLD = 5;

const ImageGallery = () => {
  const selectedProjectId = useSelector((store) => store.localVariables.projectId);
  const {
    images,
    allImagesData,
    pageNumber,
    setPageNumber,
    hasMore,
    loading,
    loadingMore,
    fetchImages,
    resetGallery,
  } = useImageGallery(selectedProjectId);

  const { openModal } = useModal();

  const yesterday = moment().subtract(1, 'days').format('YYYY-MM-DD');

  const [selectedFilters, setSelectedFilters] = useState({
    building: [],
    floor: [],
    activity: [],
    uploadedBy: [],
    workCategory: [],
    workArea: [],
    startDate: "",
    endDate: "",
  });

  const [appliedFilters, setAppliedFilters] = useState({
    buildingIds: null,
    floorIds: null,
    activityIds: null,
    uploadedByIds: null,
    workCategoryIds: null,
    workAreaIds: null,
    startDate: null,
    endDate: null,
  });

  const [collapsedFilters, setCollapsedFilters] = useState({
    dateRange: false,
    building: false,
    floor: false,
    activity: false,
    uploadedBy: false,
    workCategory: false,
    workArea: false,
  });

  const [isFilterPanelOpen, setIsFilterPanelOpen] = useState(false);
  const [hoveredImage, setHoveredImage] = useState(null);

  const imageGroupRefs = useRef({});
  const loaderRef = useRef(null);
  const filterPanelRef = useRef(null);
  const filterButtonRef = useRef(null);

  useEffect(() => {
    const handleClickOutside = (event) => {
      if (
        filterPanelRef.current &&
        !filterPanelRef.current.contains(event.target) &&
        filterButtonRef.current &&
        !filterButtonRef.current.contains(event.target)
      ) {
        setIsFilterPanelOpen(false);
      }
    };

    if (isFilterPanelOpen) {
      document.addEventListener("mousedown", handleClickOutside);
    } else {
      document.removeEventListener("mousedown", handleClickOutside);
    }

    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [isFilterPanelOpen]);

  useEffect(() => {
    if (!selectedProjectId) {
      resetGallery();
      return;
    }

    resetGallery();
    fetchImages(1, appliedFilters, true);
  }, [selectedProjectId, appliedFilters]);

  useEffect(() => {
    const handleExternalEvent = (data) => {
      if (selectedProjectId === data.projectId) {
        resetGallery();
        fetchImages(1, appliedFilters, true);
      }
    };

    eventBus.on("image_gallery", handleExternalEvent);

    return () => {
      eventBus.off("image_gallery", handleExternalEvent);
    };
  }, [appliedFilters, fetchImages, selectedProjectId]);

  useEffect(() => {
    if (!loaderRef.current) return;

    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting && hasMore && !loadingMore && !loading) {
          setPageNumber((prevPageNumber) => prevPageNumber + 1);
        }
      },
      {
        root: null,
        rootMargin: "200px",
        threshold: 0.1,
      }
    );

    observer.observe(loaderRef.current);

    return () => {
      if (loaderRef.current) {
        observer.unobserve(loaderRef.current);
      }
    };
  }, [hasMore, loadingMore, loading]);

  useEffect(() => {
    if (pageNumber > 1) {
      fetchImages(pageNumber, appliedFilters);
    }
  }, [pageNumber]);

  const getUniqueValuesWithIds = useCallback((idKey, nameKey) => {
    const map = new Map();
    allImagesData.forEach(batch => {
      let id = idKey === "floorIds" ? batch.floorIds : batch[idKey];
      const name = batch[nameKey];
      if (id && name && !map.has(id)) {
        map.set(id, name);
      }
    });
    return Array.from(map.entries()).sort((a, b) => a[1].localeCompare(b[1]));
  }, [allImagesData]);

  const getUniqueUploadedByUsers = useCallback(() => {
    const uniqueUsersMap = new Map();
    allImagesData.forEach(batch => {
      batch.documents.forEach(doc => {
        if (doc.uploadedBy && doc.uploadedBy.id) {
          const fullName = `${doc.uploadedBy.firstName || ""} ${doc.uploadedBy.lastName || ""}`.trim();
          if (fullName) {
            uniqueUsersMap.set(doc.uploadedBy.id, fullName);
          }
        }
      });
    });
    return Array.from(uniqueUsersMap.entries()).sort((a, b) => a[1].localeCompare(b[1]));
    return Array.from(uniqueUsersMap.entries()).sort((a, b) => a[1].localeCompare(b[1]));
  }, [allImagesData]);

  const buildings = getUniqueValuesWithIds("buildingId", "buildingName");
  const floors = getUniqueValuesWithIds("floorIds", "floorName");
  const activities = getUniqueValuesWithIds("activityId", "activityName");
  const workAreas = getUniqueValuesWithIds("workAreaId", "workAreaName");
  const uploadedByUsers = getUniqueUploadedByUsers();
  const workCategories = getUniqueValuesWithIds("workCategoryId", "workCategoryName");

  const toggleFilter = useCallback((type, itemId, itemName) => {
    setSelectedFilters((prev) => {
      const current = prev[type];
      const isSelected = current.some((item) => item[0] === itemId);

      const newArray = isSelected
        ? current.filter((item) => item[0] !== itemId)
        : [...current, [itemId, itemName]];

      return {
        ...prev,
        [type]: newArray,
      };
    });
  }, []);

  const setDateRange = useCallback(({ startDate, endDate }) => {
    setSelectedFilters((prev) => ({
      ...prev,
      startDate: startDate || "",
      endDate: endDate || "",
    }));
  }, []);

  const toggleCollapse = useCallback((type) => {
    setCollapsedFilters((prev) => ({
      ...prev,
      [type]: !prev[type],
    }));
  }, []);

  const handleApplyFilters = useCallback(() => {
    const payload = {
      buildingIds: selectedFilters.building.length ? selectedFilters.building.map((item) => item[0]) : null,
      floorIds: selectedFilters.floor.length ? selectedFilters.floor.map((item) => item[0]) : null,
      workAreaIds: selectedFilters.workArea.length ? selectedFilters.workArea.map((item) => item[0]) : null,
      workCategoryIds: selectedFilters.workCategory.length ? selectedFilters.workCategory.map((item) => item[0]) : null,
      activityIds: selectedFilters.activity.length ? selectedFilters.activity.map((item) => item[0]) : null,
      uploadedByIds: selectedFilters.uploadedBy.length ? selectedFilters.uploadedBy.map((item) => item[0]) : null,
      startDate: selectedFilters.startDate || null,
      endDate: selectedFilters.endDate || null,
    };

    const areFiltersChanged = Object.keys(payload).some(key => {
      const oldVal = appliedFilters[key];
      const newVal = payload[key];
      if (Array.isArray(oldVal) && Array.isArray(newVal)) {
        if (oldVal.length !== newVal.length) return true;
        const oldSet = new Set(oldVal);
        const newSet = new Set(newVal);
        for (const item of newSet) {
          if (!oldSet.has(item)) return true;
        }
        return false;
      }
      if ((oldVal === null && newVal === "") || (oldVal === "" && newVal === null)) return false;
      return oldVal !== newVal;
    });

    if (areFiltersChanged) {
      setAppliedFilters(payload);
      resetGallery();
    }
  }, [selectedFilters, appliedFilters]);

  const handleClearAllFilters = useCallback(() => {
    const initialStateSelected = {
      building: [],
      floor: [],
      activity: [],
      uploadedBy: [],
      workCategory: [],
      workArea: [],
      startDate: "",
      endDate: "",
    };
    setSelectedFilters(initialStateSelected);

    const initialStateApplied = {
      buildingIds: null,
      floorIds: null,
      activityIds: null,
      uploadedByIds: null,
      workCategoryIds: null,
      workAreaIds: null,
      startDate: null,
      endDate: null,
    };
    setAppliedFilters(initialStateApplied);
    resetGallery();
  }, []);

  const scrollLeft = useCallback((key) => {
    imageGroupRefs.current[key]?.scrollBy({ left: -200, behavior: "smooth" });
  }, []);

  const scrollRight = useCallback((key) => {
    imageGroupRefs.current[key]?.scrollBy({ left: 200, behavior: "smooth" });
  }, []);

  const renderFilterCategory = (label, items, type) => (
    <div className={`dropdown my-2 ${collapsedFilters[type] ? "collapsed" : ""}`}>
      <div className="dropdown-header bg-label-primary" onClick={() => toggleCollapse(type)}>
        <strong>{label}</strong>
        <div className="header-controls">
          {type === "dateRange" && (selectedFilters.startDate || selectedFilters.endDate) && (
            <button
              className="clear-button"
              onClick={(e) => {
                e.stopPropagation();
                setSelectedFilters((prev) => ({ ...prev, startDate: "", endDate: "" }));
              }}
            >
              Clear
            </button>
          )}
          {type !== "dateRange" && selectedFilters[type]?.length > 0 && (
            <button
              className="clear-button"
              onClick={(e) => {
                e.stopPropagation();
                setSelectedFilters((prev) => ({ ...prev, [type]: [] }));
              }}
            >
              Clear
            </button>
          )}
          <span className="collapse-icon">{collapsedFilters[type] ? '+' : '-'}</span>
        </div>
      </div>
      {!collapsedFilters[type] && (
        <div className="dropdown-content">
          {type === "dateRange" ? (
            <div className="date-range-inputs">
              <DateRangePicker
                onRangeChange={setDateRange}
                endDateMode="today"
                endDateMode="today"
                startDate={selectedFilters.startDate}
                endDate={selectedFilters.endDate}
              />
            </div>
          ) : (
            items.map(([itemId, itemName]) => (
              <label key={itemId}>
                <input
                  type="checkbox"
                  checked={selectedFilters[type].some((item) => item[0] === itemId)}
                  onChange={() => toggleFilter(type, itemId, itemName)}
                />
                {itemName}
              </label>
            ))
          )}
        </div>
      )}
    </div>
  );

  return (
    <div className={`gallery-container container-fluid ${isFilterPanelOpen ? "filter-panel-open-end" : ""}`}>
      <Breadcrumb data={[{ label: "Home", link: "/" }, { label: "Gallary", link: null }]} />
      <div className="main-content">
        <button
          className={`filter-button btn-primary ${isFilterPanelOpen ? "closed-icon" : ""}`}
          onClick={() => setIsFilterPanelOpen(!isFilterPanelOpen)}
          ref={filterButtonRef}
        >
          {isFilterPanelOpen ? <i className="fa-solid fa-times fs-5"></i> : <i className="fa-solid fa-filter ms-1 fs-5"></i>}
        </button>

        <div className="activity-section">
          {loading && pageNumber === 1 ? (
            <div className="spinner-container"><div className="spinner" /></div>
          ) : images.length > 0 ? (
            images.map((batch) => {
              const firstDoc = batch.documents[0];
              const userName = `${firstDoc?.uploadedBy?.firstName || ""} ${firstDoc?.uploadedBy?.lastName || ""}`.trim();
              const date = formatUTCToLocalTime(firstDoc?.uploadedAt);
              const showScrollButtons = batch.documents.length > SCROLL_THRESHOLD;

              return (
                <div key={batch.batchId} className="grouped-section">
                  <div className="group-heading">
                    <div className="d-flex flex-column">
                      <div className="d-flex align-items-center mb-1">
                        <Avatar size="xs" firstName={firstDoc?.uploadedBy?.firstName} lastName={firstDoc?.uploadedBy?.lastName} className="me-2" />
                        <div className="d-flex flex-column align-items-start">
                          <strong className="user-name-text">{userName}</strong>
                          <span className="me-2">{date}</span>
                        </div>
                      </div>
                    </div>
                    <div className="location-line">
                      <div>{batch.buildingName} &gt; {batch.floorName} &gt; <strong>{batch.workAreaName || "Unknown"} &gt; {batch.activityName}</strong></div>
                      {batch.workCategoryName && (
                        <div className="work-category-display ms-2">
                          <span className="badge bg-label-primary rounded-pill d-flex align-items-center gap-1">
                            {batch.workCategoryName}
                          </span>
                        </div>
                      )}
                    </div>
                  </div>
                  <div className="image-group-wrapper">
                    {showScrollButtons && <button className="scroll-arrow left-arrow" onClick={() => scrollLeft(batch.batchId)}>&#8249;</button>}
                    <div className="image-group-horizontal" ref={(el) => (imageGroupRefs.current[batch.batchId] = el)}>
                      {batch.documents.map((doc, idx) => {
                        const hoverDate = moment(doc.uploadedAt).format("DD-MM-YYYY");
                        const hoverTime = moment(doc.uploadedAt).format("hh:mm A");

                        return (
                          <div key={doc.id} className="image-card" onClick={() => openModal(<ImagePop batch={batch} initialIndex={idx} />)} onMouseEnter={() => setHoveredImage(doc)} onMouseLeave={() => setHoveredImage(null)}>
                            <div className="image-wrapper">
                              <img src={doc.url} alt={`Image ${idx + 1}`} />
                            </div>
                            {hoveredImage === doc && (
                              <div className="image-hover-description">
                                <p><strong>Date:</strong> {hoverDate}</p>
                                <p><strong>Time:</strong> {hoverTime}</p>
                                <p><strong>Activity:</strong> {batch.activityName}</p>
                              </div>
                            )}
                          </div>
                        );
                      })}
                    </div>
                    {showScrollButtons && <button className="scroll-arrow right-arrow" onClick={() => scrollRight(batch.batchId)}>&#8250;</button>}
                  </div>
                </div>
              );
            })
          ) : (
            !loading && <p style={{ textAlign: "center", color: "#777", marginTop: "50px" }}>No images match the selected filters.</p>
          )}
          <div ref={loaderRef} style={{ height: '50px', margin: '20px 0', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
            {loadingMore && hasMore && <div className="spinner" />}
            {!hasMore && !loading && images.length > 0 && <p style={{ color: '#aaa' }}>You've reached the end of the images.</p>}
          </div>
        </div>
      </div>

      <div className={`offcanvas offcanvas-end ${isFilterPanelOpen ? "show" : ""}`} tabIndex="-1" id="filterOffcanvas" aria-labelledby="filterOffcanvasLabel" ref={filterPanelRef}>
        <div className="offcanvas-header">
          <h5 className="offcanvas-title" id="filterOffcanvasLabel">Filters</h5>
          <button type="button" className="btn-close" onClick={() => setIsFilterPanelOpen(false)} aria-label="Close" />
        </div>
        <div className="filter-actions mt-auto mx-2">
          <button className="btn btn-secondary btn-xs" onClick={handleClearAllFilters}>Clear All</button>
          <button className="btn btn-primary btn-xs" onClick={handleApplyFilters}>Apply Filters</button>
        </div>
        <div className="offcanvas-body d-flex flex-column">
          {renderFilterCategory("Date Range", [], "dateRange")}
          {renderFilterCategory("Building", buildings, "building")}
          {renderFilterCategory("Floor", floors, "floor")}
          {renderFilterCategory("Work Area", workAreas, "workArea")}
          {renderFilterCategory("Activity", activities, "activity")}
          {renderFilterCategory("Uploaded By (User)", uploadedByUsers, "uploadedBy")}
          {renderFilterCategory("Work Category", workCategories, "workCategory")}
        </div>
      </div>
    </div>
  );
};

export default ImageGallery;
