import React, {
  useCallback,
  useEffect,
  useRef,
  useState,
  useGlobal,
} from "reactn";
import { Image, Pressable, Text, View } from "react-native";
import * as ImagePicker from "expo-image-picker";
import moment from "moment";
import { useActionSheet } from "@expo/react-native-action-sheet";
import * as DocumentPicker from "expo-document-picker";
import Compressor from "react-native-compressor";
import useMinuit from "react-native-minuit/src/hooks/useMinuit";

import { arrayUnion } from "../config/firebase";

import Style, { gutterConstant, mainBorderRadius } from "../styles/Style";
import { Fonts, Palette } from "../styles";
import { icons } from "../assets";

import { uploadFileToFirebase } from "../helpers/uploadToFirebase";
import useLayoutType from "../hooks/useLayoutType";

const NATIVE_OPTIONS = [
  "Importer depuis la galerie",
  "Ajouter un fichier",
  "Prendre une photo ou une vidéo",
  "Annuler",
];

const DocumentDropZone = ({
  containerStyle = {},

  documentID = null,
  documentExists = false,

  collectionRef = null,

  setFiles = null,
  customElement = null,
  shouldReturnObject = false,
}) => {
  const dropRef = useRef(null);

  const [isDragging, setIsDragging] = useState(false);

  const { setIsLoading, setTooltip } = useMinuit();
  const { isDesktop, isWeb, isNative } = useLayoutType();
  const { showActionSheetWithOptions } = useActionSheet();

  useEffect(() => {
    if (isWeb && dropRef.current) {
      const el = dropRef.current;

      const handleDragIn = (e) => {
        e.preventDefault();
        e.stopPropagation();
        setIsDragging(true);
      };

      const handleDragOut = (e) => {
        e.preventDefault();
        e.stopPropagation();
        if (!dropRef.current.contains(e.relatedTarget)) {
          console.log("drag left");
          setIsDragging(false);
        }
      };

      const handleDrop = (e) => {
        e.preventDefault();
        e.stopPropagation();
        setIsDragging(false);

        let files = [...e.dataTransfer.files];

        if (files.length > 0) {
          for (const file of files) {
            handleWebFile({ file });
          }
        }
      };

      el.addEventListener("dragenter", handleDragIn);
      el.addEventListener("dragleave", handleDragOut);
      el.addEventListener("dragover", (e) => e.preventDefault());
      el.addEventListener("drop", handleDrop);

      return () => {
        el.removeEventListener("dragenter", handleDragIn);
        el.removeEventListener("dragleave", handleDragOut);
        el.removeEventListener("dragover", (e) => e.preventDefault());
        el.removeEventListener("drop", handleDrop);
      };
    }
  }, [dropRef?.current]);

  const handleWebFile = ({ file }) => {
    try {
      const { type = "" } = file;
      const reader = new FileReader();

      reader.onloadend = () => {
        const base64 = reader.result.split(",")[1]; // Vous pourriez avoir besoin de cette valeur base64 pour un upload direct
        const uri = reader.result; // URI en base64 du fichier

        console.log("file", file);

        onUploadDocument({ files: [{ name: file.name, uri, type }] });
      };

      reader.onerror = (err) => {
        console.error("FileReader error", err);
      };

      reader.readAsDataURL(file); // Lire le fichier et déclencher reader.onloadend lorsque c'est fait
    } catch (error) {
      console.log(error);
      setTooltip({ text: error.message, type: "error" });
    }
  };

  const onAddFile = async ({} = {}) => {
    try {
      if (isNative) {
        const cancelButtonIndex = NATIVE_OPTIONS.length - 1;

        showActionSheetWithOptions(
          {
            options: NATIVE_OPTIONS,
            cancelButtonIndex,
            userInterfaceStyle: "dark",
            ...Style.actionSheet,
          },
          async (selectedIndex) => {
            if (selectedIndex !== cancelButtonIndex) {
              switch (selectedIndex) {
                case 0:
                  onChooseLibrary();
                  break;
                case 1:
                  onChooseDocumentPicker();
                  break;
                case 2:
                  onTakePicture();
                  break;
                default:
                  break;
              }
            }
          }
        );
      } else {
        onChooseDocumentPicker();
      }
    } catch (error) {
      console.log(error);
      setTooltip({ text: error.message, type: "error" });
    } finally {
      setIsLoading(false);
    }
  };

  const onChooseLibrary = async ({} = {}) => {
    const result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      allowsEditing: false,
      quality: 3,
    });

    if (result?.assets?.[0]?.uri) {
      const { uri, fileName = "" } = result?.assets?.[0];

      onUploadDocument({
        files: [
          {
            name: getAssetName({ fileName, uri }),
            uri,
            type: "IMAGE",
          },
        ],
      });
    } else {
      throw new Error("Aucune image sélectionnée");
    }
  };

  const onChooseDocumentPicker = async ({} = {}) => {
    const result = await DocumentPicker.getDocumentAsync({
      type: "*/*",
      copyToCacheDirectory: false,
    });

    if (result?.assets?.length > 0) {
      const { name = "", uri = null } = result?.assets[0] || {};

      if (!uri) {
        throw new Error("Erreur lors de l'ajout du document");
      }

      onUploadDocument({
        files: [
          {
            name: name || getDefaultFileName(),
            uri,
          },
        ],
      });
    } else {
      console.log(result);
      throw new Error("Erreur lors de l'ajout du document");
    }
  };

  const onTakePicture = useCallback(async () => {
    const { status } = await ImagePicker.requestCameraPermissionsAsync();

    if (status !== "granted") {
      throw new Error("Permissions caméra non accordées");
    }

    const result = await ImagePicker.launchCameraAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      allowsEditing: true,
      quality: 1,
    });

    if (result?.assets?.[0]?.uri) {
      const { uri, fileName = "" } = result?.assets?.[0];

      onUploadDocument({
        files: [
          {
            name: getAssetName({ fileName, uri }),
            uri,
            type: "IMAGE",
          },
        ],
      });
    } else {
      throw new Error("Aucune image sélectionnée");
    }
  }, []);

  const getDefaultFileName = () => {
    const randomID = Math.random().toString(36).substring(7);
    return `${moment().format(`DD_MM_YYYY_HH_mm_ss`)}_${randomID}`;
  };

  const getAssetName = ({ fileName = "", uri = "" }) => {
    let name = fileName;

    if (!name && uri?.startsWith("file://")) {
      const splittedArray = uri?.split("/") || [];
      name = splittedArray?.[splittedArray?.length - 1] || "";
    }

    if (!name?.length) {
      let extension = uri?.split(";")?.[0]?.split("/")?.[1] || "";

      const defaultFileName = getDefaultFileName();

      if (extension?.length) {
        name = `${defaultFileName}.${extension}`;
      } else {
        name = `${defaultFileName}`;
      }
    }

    return name;
  };

  const onUploadDocument = async ({ files = [] } = {}) => {
    try {
      setIsLoading(true);

      const filesToUpdate = [];

      await Promise.all(
        files.map(async (file) => {
          const { name = "", uri = null } = file;

          console.log(file);

          if (!uri) {
            throw new Error("Erreur lors de l'ajout du document");
          }

          const fileName = name || getDefaultFileName();
          let type = "FILE";

          if (name?.toLowerCase()?.match(/\.(jpeg|jpg|gif|png)$/) != null) {
            type = "IMAGE";
          }

          if (name?.toLowerCase()?.match(/\.(mp4|mov|avi|mkv)$/) != null) {
            type = "VIDEO";
          }

          let compressedURI = uri;
          let thumbnailURI = null;

          if (isNative) {
            if (type === "IMAGE") {
              compressedURI = await Compressor.Image.compress(uri, {
                compressionMethod: "manual",
                maxWidth: 1000,
                quality: 0.8,
              });
            } else if (type === "VIDEO") {
              compressedURI = await Compressor.Video.compress(uri);
            }
          }

          const { resultURI = null } = await uploadFileToFirebase({
            uri: compressedURI,
            path: `documents/${documentID}/files/${fileName}`,
          });

          if (resultURI) {
            if (shouldReturnObject) {
              filesToUpdate.push({
                name: fileName,
                uri: resultURI,
                type,
                thumbnailURI,
              });
            } else {
              filesToUpdate.push(resultURI);
            }
          } else {
            console.log("resultURI is null");
          }
        })
      );

      if (filesToUpdate.length > 0) {
        if (documentExists) {
          await collectionRef.doc(documentID).update({
            files: arrayUnion(...filesToUpdate),
          });
        }

        if (setFiles) {
          setFiles((prev) => [...prev, ...filesToUpdate]);
        }
      }

      setTooltip({ text: "Document(s) ajouté(s) avec succès" });
    } catch (error) {
      console.log(error);
      setTooltip({ text: error.message, type: "error" });
    } finally {
      setIsLoading(false);
    }
  };

  if (!documentID) {
    return null;
  }

  return (
    <View ref={dropRef}>
      <Pressable onPress={onAddFile}>
        {customElement?.() || (
          <View
            style={{
              ...Style.containerCenter,
              backgroundColor: isDragging
                ? Palette.transparentGreen
                : Palette.transparentPrimary,
              borderRadius: mainBorderRadius,
              borderStyle: "dashed",
              borderWidth: 2,
              borderColor: isDragging ? Palette.green : Palette.primary,
              ...containerStyle,
            }}
          >
            <Image
              source={icons.screenshot}
              style={{
                ...Style.iconLarge,
                marginBottom: gutterConstant,
              }}
            />
            <Text
              style={{
                ...Fonts({ type: "default" }),
                textAlign: "center",
                color: Palette.white,
              }}
            >
              {isWeb && isDesktop
                ? `Glissez-déposez ici\nles fichiers, images et vidéos\nà ajouter.`
                : "Ajouter une image,\nun fichier ou une vidéo."}
            </Text>
          </View>
        )}
      </Pressable>
    </View>
  );
};

export default DocumentDropZone;
