import { useApolloClient } from "@apollo/client";
import * as MediaLibrary from "expo-media-library";
import _ from "lodash";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import {
  ActivityIndicator,
  Alert,
  Modal,
  ScrollView,
  StyleSheet,
  Text,
  View,
} from "react-native";
import { ProgressBar } from "react-native-paper";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.analytics";
import {
  selectCurrentCameraJobId,
  selectDeleteAfterUpload,
} from "../../redux/app/app.selectors";
import {
  selectBodyshop,
  selectCurrentUser,
} from "../../redux/user/user.selectors";
import { formatBytes } from "../../util/document-upload.utility";
import { handleLocalUpload } from "../../util/local-document-upload.utility";
import Toast from "react-native-toast-message";

const mapStateToProps = createStructuredSelector({
  currentUser: selectCurrentUser,
  bodyshop: selectBodyshop,
  selectedCameraJobId: selectCurrentCameraJobId,
  deleteAfterUpload: selectDeleteAfterUpload,
});

export default connect(mapStateToProps, null)(UploadProgress);

export function UploadProgress({
  currentUser,
  bodyshop,
  selectedCameraJobId,
  deleteAfterUpload,
  uploads,
  forceRerender,
}) {
  const [progress, setProgress] = useState({
    loading: false,
    uploadInProgress: false,
    speed: 0,
    files: {}, //uri is the key, value is progress
  });

  let filesToDelete = [];
  const client = useApolloClient();

  const { t } = useTranslation();

  useEffect(() => {
    //Set the state of uploads to do.

    if (uploads) onDone(uploads);
  }, [uploads]);

  //if (!uploads) return null;

  function handleOnSuccess(id, asset, { duration }) {
    //If it's not in production, show a toast with the time.
    Toast.show({
      type: "success",
      text1: `${duration} - Upload completed for ${asset.filename}.`,
      //
      //   text2: duration,
    });

    logImEXEvent("imexmobile_successful_upload");
    filesToDelete.push(asset);
    setProgress((progress) => ({
      ...progress,
      action: t("mediabrowser.labels.converting"),
      files: {
        ...progress.files,
        [id]: {
          ...progress.files[id],
          percent: 1,
          action: t("mediabrowser.labels.converting"),
        },
      },
      // });
    }));
  }

  function handleOnProgress(uri, percent, loaded) {
    setProgress((progress) => ({
      ...progress,
      // speed: loaded - progress.files[uri].loaded,
      action:
        percent === 1
          ? t("mediabrowser.labels.converting")
          : t("mediabrowser.labels.uploading"),
      files: {
        ...progress.files,
        [uri]: {
          ...progress.files[uri],
          percent,
          speed: loaded - progress.files[uri].loaded,
          action:
            percent === 1
              ? t("mediabrowser.labels.converting")
              : t("mediabrowser.labels.uploading"),
          loaded: loaded,
        },
      },
    }));
  }
  function handleOnError(id, error) {
    logImEXEvent("imexmobile_upload_documents_error");
    Toast.show({
      type: "error",
      text1: "Unable to upload documents.",
      text2: (error && error.message) || JSON.stringify(error),
      autoHide: false,
    });
    setProgress((progress) => ({
      ...progress,
      action: t("mediabrowser.labels.converting"),
      files: {
        ...progress.files,
        [id]: {
          ...progress.files[id],
          percent: 1,
          action: t("mediabrowser.labels.converting"),
        },
      },
      // });
    }));
  }

  const onDone = async (data) => {
    //Validate to make sure the totals for the file sizes do not exceed the total on the job.
    setProgress({
      files: _.keyBy(data, "id"),
      loading: true,
      uploadInProgress: true,
    });

    //Sequentially await the proms.

    // for (const file of data) {
    //   await CreateUploadProm(file);
    // }

    for (var i = 0; i < data.length + 4; i = i + 4) {
      let proms = [];
      if (data[i]) {
        proms.push(CreateUploadProm(data[i]));
      }
      if (data[i + 1]) {
        proms.push(CreateUploadProm(data[i + 1]));
      }
      if (data[i + 2]) {
        proms.push(CreateUploadProm(data[i + 2]));
      }
      if (data[i + 3]) {
        proms.push(CreateUploadProm(data[i + 3]));
      }

      await Promise.all(proms);
    }

    if (deleteAfterUpload) {
      try {
        const a = await MediaLibrary.getAssetsAsync();

        const res = await Promise.all(
          filesToDelete.map((f) => {
            return MediaLibrary.removeAssetsFromAlbumAsync(f, f.albumId);
          })
        );

        const deleteResult = await MediaLibrary.deleteAssetsAsync(
          filesToDelete.map((f) => f.id)
        );
      } catch (error) {
        console.log("Unable to delete picture.", error);
      }
    }
    filesToDelete = [];
    setProgress({
      loading: false,
      speed: 0,
      action: null,

      uploadInProgress: false,
      files: {}, //uri is the key, value is progress
    });

    forceRerender();
  };

  const CreateUploadProm = async (p) => {
    let filename;
    filename = p.filename || p.uri.split("/").pop();

    await handleLocalUpload({
      ev: {
        filename,
        mediaId: p.id,
        onError: (error) => handleOnError(p.id, error),
        onProgress: ({ percent, loaded }) =>
          handleOnProgress(p.id, percent, loaded),
        onSuccess: ({ duration }) => handleOnSuccess(p.id, p, { duration }),
        file: p,
      },
      context: {
        bodyshop: bodyshop,
        jobid:
          selectedCameraJobId !== "temp" ? selectedCameraJobId : "temporary",
      },
    });

    //Set the state to mark that it's done.
    setProgress((progress) => ({
      ...progress,
      action: null,
      speed: 0,
      files: {
        ...progress.files,
        [p.id]: {
          ...progress.files[p.id],
          action: null,
        },
      },
    }));
  };

  return (
    <Modal
      visible={progress.uploadInProgress}
      animationType="slide"
      transparent={true}
      onRequestClose={() => {}}
    >
      <View style={styles.modal}>
        {progress.loading && <ActivityIndicator />}

        <ScrollView contentContainerStyle={styles.centeredView}>
          {Object.keys(progress.files).map((key) => (
            <View key={progress.files[key].id} style={styles.progressItem}>
              <Text style={styles.progressText}>
                {progress.files[key].filename}
              </Text>
              <View style={styles.progressBarContainer}>
                <ProgressBar
                  progress={progress.files[key].percent}
                  style={styles.progress}
                  color={progress.files[key].percent === 1 ? "green" : "blue"}
                />
                {progress.files[key].speed !== 0 &&
                progress.files[key].speed &&
                !isNaN(progress.files[key].speed) ? (
                  <Text>{`${formatBytes(progress.files[key].speed)}/sec`}</Text>
                ) : null}
              </View>
            </View>
          ))}
        </ScrollView>
      </View>
    </Modal>
  );
}
const styles = StyleSheet.create({
  modal: {
    flex: 1,
    marginTop: 80,
    marginBottom: 60,
    marginLeft: 20,
    marginRight: 20,
    backgroundColor: "white",
    borderRadius: 20,
    padding: 18,
    shadowColor: "#000",
    shadowOffset: {
      width: 0,
      height: 2,
    },
    shadowOpacity: 0.25,
    shadowRadius: 4,
    elevation: 5,
  },
  centeredView: {
    flex: 1,
    // justifyContent: "center",
    // alignItems: "center",
    marginTop: 22,
  },
  progressItem: {
    display: "flex",
    flexDirection: "row",
    alignItems: "center",
    marginBottom: 12,
    marginLeft: 12,
    marginRight: 12,
  },
  progressText: {
    flex: 1,
  },
  progressBarContainer: {
    flex: 3,
    marginLeft: 12,
    marginRight: 12,
  },
});
