import axios from "axios";
import { Result, theme } from "antd";
import * as markerjs2 from "markerjs2";
import { useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
import { handleUpload } from "../documents-local-upload/documents-local-upload.utility";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
import {
  addGreyscaleButtonToMarkerArea,
  addImageHistoryUndoToMarkerArea,
  applyGreyscaleToMarkerAreaImage,
  setMarkerAreaImageSource
} from "./document-editor.utility";

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

export function DocumentEditorLocalComponent({ imageUrl, filename, jobid }) {
  const imgRef = useRef(null);
  const [loading, setLoading] = useState(false);
  const [uploaded, setuploaded] = useState(false);
  const [loadedImageUrl, setLoadedImageUrl] = useState(null);
  const [imageLoaded, setImageLoaded] = useState(false);
  const [imageLoading, setImageLoading] = useState(true);
  const markerArea = useRef(null);
  const imageHistory = useRef([]);
  const { t } = useTranslation();
  const { token } = theme.useToken();
  const notification = useNotification();
  const [uploading, setUploading] = useState(false);

  const triggerUpload = useCallback(
    async (dataUrl) => {
      if (uploading) return;
      setUploading(true);
      setLoading(true);
      const blob = await b64toBlob(dataUrl);
      const nameWithoutExt = filename.split(".").slice(0, -1).join(".").trim();
      const parts = nameWithoutExt.split("-");
      const baseParts = [];
      for (let i = 0; i < parts.length; i++) {
        if (/^\d+$/.test(parts[i])) {
          break;
        }
        baseParts.push(parts[i]);
      }
      const adjustedBase = baseParts.length > 0 ? baseParts.join("-") : "edited";
      const adjustedFilename = `${adjustedBase}.jpg`;
      const file = new File([blob], adjustedFilename, { type: "image/jpeg" });

      handleUpload({
        ev: {
          file: file,
          filename: adjustedFilename,
          onSuccess: () => {
            setUploading(false);
            setLoading(false);
            setuploaded(true);
          },
          onError: () => {
            setUploading(false);
            setLoading(false);
          }
        },
        context: {
          jobid: jobid,
          callback: () => {} // Optional callback
        },
        notification
      });
    },
    [filename, jobid, notification, uploading]
  );

  const handleGreyscale = useCallback(() => {
    if (!imgRef.current || loading || uploaded || imageLoading || !imageLoaded) return;

    imageHistory.current.push(imgRef.current.src);
    applyGreyscaleToMarkerAreaImage(markerArea.current, imgRef.current);
  }, [imageLoaded, imageLoading, loading, uploaded]);

  const undoImageEdit = useCallback(() => {
    if (!imgRef.current) return;

    const previousSrc = imageHistory.current.pop();

    if (previousSrc) {
      setMarkerAreaImageSource(markerArea.current, imgRef.current, previousSrc);
    }
  }, []);

  useEffect(() => {
    if (imgRef.current !== null && imageLoaded && !markerArea.current) {
      // create a marker.js MarkerArea
      markerArea.current = new markerjs2.MarkerArea(imgRef.current);

      // attach an event handler to assign annotated image back to our image element
      markerArea.current.addEventListener("close", () => {
        // NO OP
      });

      markerArea.current.addEventListener("render", (event) => {
        const dataUrl = event.dataUrl;
        imgRef.current.src = dataUrl;
        markerArea.current.close();
        triggerUpload(dataUrl);
      });
      // launch marker.js

      markerArea.current.renderAtNaturalSize = true;
      markerArea.current.renderImageType = "image/jpeg";
      markerArea.current.renderImageQuality = 1;
      //markerArea.current.settings.displayMode = "inline";
      markerArea.current.show();
      addGreyscaleButtonToMarkerArea(markerArea.current, handleGreyscale, t("documents.labels.greyscale"));
      addImageHistoryUndoToMarkerArea(markerArea.current, () => imageHistory.current.length > 0, undoImageEdit);
    }
  }, [handleGreyscale, imageLoaded, t, triggerUpload, undoImageEdit]);

  useEffect(() => {
    if (!imageUrl) return;
    const controller = new AbortController();

    const loadImage = async () => {
      setImageLoaded(false);
      setImageLoading(true);
      try {
        const response = await axios.get(imageUrl, { responseType: "blob", signal: controller.signal });
        const blobUrl = URL.createObjectURL(response.data);
        imageHistory.current = [];
        setLoadedImageUrl((prevUrl) => {
          if (prevUrl) URL.revokeObjectURL(prevUrl);
          return blobUrl;
        });
      } catch (error) {
        if (axios.isCancel?.(error) || error.name === "CanceledError") {
          // request was aborted — safe to ignore
          return;
        }
        console.error("Failed to fetch image blob", error);
      } finally {
        if (!controller.signal.aborted) {
          setImageLoading(false);
        }
      }
    };
    loadImage();
    return () => {
      controller.abort();
    };
  }, [imageUrl]);

  useEffect(() => {
    return () => {
      if (loadedImageUrl) {
        URL.revokeObjectURL(loadedImageUrl);
      }
    };
  }, [loadedImageUrl]);

  async function b64toBlob(url) {
    const res = await fetch(url);
    return await res.blob();
  }

  return (
    <div style={{ background: token.colorBgBase, color: token.colorText, minHeight: "100vh" }}>
      {!loading && !uploaded && loadedImageUrl && (
        <img
          ref={imgRef}
          src={loadedImageUrl}
          alt="sample"
          onLoad={() => setImageLoaded(true)}
          onError={(error) => {
            console.error("Failed to load image", error);
          }}
          style={{ maxWidth: "90vw", maxHeight: "90vh" }}
        />
      )}
      {(loading || imageLoading || !imageLoaded) && !uploaded && (
        <LoadingSpinner message={t("documents.labels.uploading")} />
      )}
      {uploaded && (
        <Result
          status="success"
          title={<span style={{ color: token.colorText }}>{t("documents.successes.edituploaded")}</span>}
        />
      )}
    </div>
  );
}

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