import { EditFilled, SyncOutlined } from "@ant-design/icons";
import { Button, Card, Col, Row, Space } from "antd";
import axios from "axios";
import i18n from "i18next";
import { isFunction } from "lodash";
import { useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import Lightbox from "react-image-lightbox";
import "react-image-lightbox/style.css";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import DocumentsUploadImgproxyComponent from "../documents-upload-imgproxy/documents-upload-imgproxy.component";
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
import LocalMediaGrid from "../jobs-documents-local-gallery/local-media-grid.component";
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
import JobsDocumentsDownloadButton from "./jobs-document-imgproxy-gallery.download.component";
import JobsDocumentsGalleryReassign from "./jobs-document-imgproxy-gallery.reassign.component";
import JobsDocumentsDeleteButton from "./jobs-documents-imgproxy-gallery.delete.component";
import JobsDocumentsGallerySelectAllComponent from "./jobs-documents-imgproxy-gallery.selectall.component";

const mapStateToProps = createStructuredSelector({
  bodyshop: selectBodyshop
});
const mapDispatchToProps = () => ({});

function JobsDocumentsImgproxyComponent({
  bodyshop,
  data,
  jobId,
  refetch,
  billId,
  billsCallback,
  totalSize,
  downloadIdentifier,
  ignoreSizeLimit
}) {
  const [galleryImages, setGalleryImages] = useState({ images: [], other: [] });
  const { t } = useTranslation();
  const [modalState, setModalState] = useState({ open: false, index: 0 });
  const [previewUrls, setPreviewUrls] = useState({});
  const [previewError, setPreviewError] = useState(null);
  const previewUrlsRef = useRef({});

  const fetchThumbnails = useCallback(() => {
    fetchImgproxyThumbnails({ setStateCallback: setGalleryImages, jobId, billId });
  }, [jobId, billId, setGalleryImages]);

  useEffect(() => {
    if (data) {
      fetchThumbnails();
    }
  }, [data, fetchThumbnails]);

  useEffect(() => {
    return () => {
      Object.values(previewUrlsRef.current).forEach(URL.revokeObjectURL);
    };
  }, []);

  const selectedImage = modalState.open ? galleryImages.images[modalState.index] : null;

  useEffect(() => {
    if (!modalState.open || !selectedImage?.id) return;

    if (previewUrlsRef.current[selectedImage.id]) {
      setPreviewError(null);
      return;
    }

    const controller = new AbortController();

    async function loadPreviewImage() {
      setPreviewError(null);

      try {
        const response = await axios.post(
          "/media/imgproxy/original",
          { documentId: selectedImage.id },
          {
            responseType: "blob",
            signal: controller.signal
          }
        );
        const blobUrl = URL.createObjectURL(response.data);

        previewUrlsRef.current = {
          ...previewUrlsRef.current,
          [selectedImage.id]: blobUrl
        };
        setPreviewUrls(previewUrlsRef.current);
      } catch (error) {
        if (axios.isCancel?.(error) || error.name === "CanceledError") return;

        console.error("Failed to fetch original image blob", error);
        setPreviewError(error);
      }
    }

    loadPreviewImage();

    return () => {
      controller.abort();
    };
  }, [modalState.open, selectedImage?.id]);

  useEffect(() => {
    if (modalState.open && !selectedImage) {
      setModalState({ open: false, index: 0 });
    }
  }, [modalState.open, selectedImage]);

  const openEditorForImage = useCallback((image) => {
    if (!image?.id) return;

    const newWindow = window.open(
      `${window.location.protocol}//${window.location.host}/edit?documentId=${image.id}`,
      "_blank",
      "noopener,noreferrer"
    );
    if (newWindow) newWindow.opener = null;
  }, []);

  const hasMediaAccess = HasFeatureAccess({ bodyshop, featureName: "media" });
  const hasMobileAccess = HasFeatureAccess({ bodyshop, featureName: "mobile" });
  const previewSrc = selectedImage ? previewUrls[selectedImage.id] : null;
  const getLightboxImageSrc = useCallback(
    (index) => {
      const image = galleryImages.images[index];
      return image ? previewUrls[image.id] || image.src : undefined;
    },
    [galleryImages.images, previewUrls]
  );

  return (
    <div>
      <Row gutter={[16, 16]}>
        <Col span={24}>
          <Space wrap>
            <Button
              onClick={() => {
                //Handle any doc refresh.

                isFunction(refetch) && refetch();

                //Do the imgproxy refresh too
                fetchThumbnails();
              }}
              icon={<SyncOutlined />}
            />
            <JobsDocumentsGallerySelectAllComponent galleryImages={galleryImages} setGalleryImages={setGalleryImages} />
            {!billId && (
              <JobsDocumentsGalleryReassign galleryImages={galleryImages} callback={fetchThumbnails || refetch} />
            )}
            <JobsDocumentsDownloadButton galleryImages={galleryImages} identifier={downloadIdentifier} jobId={jobId} />
            <JobsDocumentsDeleteButton
              galleryImages={galleryImages}
              deletionCallback={billsCallback || fetchThumbnails || refetch}
            />
          </Space>
        </Col>
        {!hasMediaAccess && (
          <Col span={24}>
            <Card>
              <UpsellComponent disableMask upsell={upsellEnum().media.general} />
            </Card>
          </Col>
        )}
        <Col span={24}>
          <Card>
            <DocumentsUploadImgproxyComponent
              jobId={jobId}
              totalSize={totalSize}
              billId={billId}
              callbackAfterUpload={
                billsCallback ||
                function () {
                  isFunction(refetch) && refetch();
                  isFunction(fetchThumbnails) && fetchThumbnails();
                }
              }
              ignoreSizeLimit={ignoreSizeLimit}
            />
          </Card>
        </Col>
        {hasMediaAccess && !hasMobileAccess && (
          <Col span={24}>
            <Card>
              <UpsellComponent upsell={upsellEnum().media.mobile} />
            </Card>
          </Col>
        )}
        <Col span={24}>
          <Card title={t("jobs.labels.documents-images")}>
            <LocalMediaGrid
              images={galleryImages.images}
              onClick={(index) => {
                setModalState({ open: true, index: index });
              }}
              onToggle={(index) => {
                setGalleryImages({
                  ...galleryImages,
                  images: galleryImages.images.map((g, idx) =>
                    index === idx ? { ...g, isSelected: !g.isSelected } : g
                  )
                });
              }}
              minColumns={4}
              expandHeight={true}
            />
          </Card>
        </Col>
        <Col span={24}>
          <Card title={t("jobs.labels.documents-other")}>
            <LocalMediaGrid
              images={galleryImages.other}
              onClick={(index) => {
                window.open(galleryImages.other[index].source, "_blank", "toolbar=0,location=0,menubar=0");
              }}
              onToggle={(index) => {
                setGalleryImages({
                  ...galleryImages,
                  other: galleryImages.other.map((g, idx) => (index === idx ? { ...g, isSelected: !g.isSelected } : g))
                });
              }}
              minColumns={4}
              expandHeight={true}
            />
          </Card>
        </Col>
        {modalState.open && selectedImage && (
          <Lightbox
            toolbarButtons={[
              <EditFilled
                key="edit"
                onClick={() => {
                  openEditorForImage(selectedImage);
                }}
              />
            ]}
            imageLoadErrorMessage={previewError ? t("general.errors.notfound") : undefined}
            mainSrc={previewSrc || selectedImage.src}
            mainSrcThumbnail={selectedImage.src}
            nextSrc={getLightboxImageSrc((modalState.index + 1) % galleryImages.images.length)}
            nextSrcThumbnail={galleryImages.images[(modalState.index + 1) % galleryImages.images.length]?.src}
            prevSrc={getLightboxImageSrc(
              (modalState.index + galleryImages.images.length - 1) % galleryImages.images.length
            )}
            prevSrcThumbnail={
              galleryImages.images[(modalState.index + galleryImages.images.length - 1) % galleryImages.images.length]
                ?.src
            }
            reactModalProps={{ ariaHideApp: false }}
            onCloseRequest={() => {
              setModalState({ open: false, index: 0 });
              setPreviewError(null);
            }}
            onMovePrevRequest={() =>
              setModalState({
                ...modalState,
                index: (modalState.index + galleryImages.images.length - 1) % galleryImages.images.length
              })
            }
            onMoveNextRequest={() =>
              setModalState({
                ...modalState,
                index: (modalState.index + 1) % galleryImages.images.length
              })
            }
          />
        )}
      </Row>
    </div>
  );
}

export default connect(mapStateToProps, mapDispatchToProps)(JobsDocumentsImgproxyComponent);

export const fetchImgproxyThumbnails = async ({ setStateCallback, jobId, billId, imagesOnly }) => {
  const result = await axios.post("/media/imgproxy/thumbnails", { jobid: jobId, billid: billId });
  const documents = result.data.reduce(
    (acc, value) => {
      if (value.type.startsWith("image")) {
        acc.images.push({
          src: value.thumbnailUrl,
          fullsize: value.originalUrl,
          height: 225,
          width: 225,
          isSelected: false,
          key: value.key,
          filename: value.key,
          extension: value.extension,
          id: value.id,
          type: value.type,
          size: value.size,
          tags: [{ value: value.type, title: value.type }]
        });
      } else {
        const fileName = value.key.split("/").pop();
        acc.other.push({
          source: value.originalUrlViaProxyPath,
          src: value.thumbnailUrl,
          fullsize: value.presignedGetUrl,
          tags: [
            {
              value: fileName,
              title: fileName
            },

            { value: value.type, title: value.type },
            ...(value.bill
              ? [
                  {
                    value: value.bill.vendor.name,
                    title: i18n.t("vendors.fields.name")
                  },
                  { value: value.bill.date, title: i18n.t("bills.fields.date") },
                  {
                    value: value.bill.invoice_number,
                    title: i18n.t("bills.fields.invoice_number")
                  }
                ]
              : [])
          ],
          height: 225,
          width: 225,
          isSelected: false,
          extension: value.extension,
          key: value.key,
          filename: value.key,
          id: value.id,
          type: value.type,
          size: value.size
        });
      }
      return acc;
    },
    { images: [], other: [] }
  );

  setStateCallback(imagesOnly ? documents.images : documents);
};
