package ch.threema.app.fragments.mediaviews;

import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ImageView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.davemorrissey.labs.subscaleview.ImageSource;
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;

import org.slf4j.Logger;

import java.io.File;
import java.lang.ref.WeakReference;

import androidx.annotation.NonNull;

import androidx.annotation.Nullable;
import ch.threema.app.R;
import ch.threema.app.utils.BitmapUtil;
import ch.threema.app.utils.ConfigUtils;
import ch.threema.storage.models.AbstractMessageModel;

import static ch.threema.base.utils.LoggingKt.getThreemaLogger;

import static ch.threema.app.utils.ActiveScreenLoggerKt.logScreenVisibility;

/**
 * This fragment is used to show images.
 */
public class ImageViewFragment extends MediaViewFragment {
    private static final Logger logger = getThreemaLogger("ImageViewFragment");

    private WeakReference<SubsamplingScaleImageView> imageViewReference;
    private WeakReference<ImageView> previewViewReference;

    private boolean uiVisibilityStatus = false;

    public ImageViewFragment() {
        super();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        logScreenVisibility(this, logger);
    }

    @Override
    protected int getFragmentResourceId() {
        return R.layout.fragment_media_viewer_image;
    }

    @Override
    protected void showThumbnail(@NonNull Drawable thumbnail) {
        if (imageViewReference.get() != null) {
            previewViewReference.get().setVisibility(View.VISIBLE);
            previewViewReference.get().setImageDrawable(thumbnail);
            imageViewReference.get().setVisibility(View.INVISIBLE);
        }
    }

    private void hideThumbnail() {
        previewViewReference.get().setVisibility(View.INVISIBLE);
    }

    @Override
    protected void created(@Nullable Bundle savedInstanceState, @NonNull ViewGroup rootView) {
        SubsamplingScaleImageView.setPreferredBitmapConfig(Bitmap.Config.ARGB_8888);

        imageViewReference = new WeakReference<>(rootView.findViewById(R.id.subsampling_image));
        previewViewReference = new WeakReference<>(rootView.findViewById(R.id.preview_image));

        imageViewReference.get().setMaxScale(8);
        imageViewReference.get().setDoubleTapZoomStyle(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);
        imageViewReference.get().setOnClickListener(
            view -> {
                showUi(uiVisibilityStatus);
                uiVisibilityStatus = !uiVisibilityStatus;
            }
        );
        imageViewReference.get().setOnImageEventListener(
            new SubsamplingScaleImageView.OnImageEventListener() {
                @Override
                public void onReady() {
                }

                @Override
                public void onImageLoaded() {
                    hideThumbnail();
                }

                @Override
                public void onPreviewLoadError(Exception e) {
                }

                @Override
                public void onImageLoadError(Exception e) {
                }

                @Override
                public void onTileLoadError(Exception e) {
                }

                @Override
                public void onPreviewReleased() {
                }
            }
        );
    }

    @Override
    protected void handleDecryptingFile() {
        //on decoding, do nothing!
    }

    @Override
    protected void handleDecryptFailure() {
        //
    }

    @Override
    protected void handleDecryptedFile(File file) {
        if (this.isAdded()) {
            try {
                showImage(file);
            } catch (Exception e) {
                logger.error("Exception", e);
            }
        }
    }

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (getRootViewReference() == null) {
            return;
        }
        getRootViewReference().getViewTreeObserver().addOnGlobalLayoutListener(
            new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (getRootViewReference() != null) {
                        getRootViewReference().getViewTreeObserver().removeOnGlobalLayoutListener(this);
                        if (imageViewReference != null && imageViewReference.get() != null) {
                            imageViewReference.get().resetScaleAndCenter();
                        }
                    }
                }
            }
        );
    }

    /**
     * Show image and hide the gif view
     *
     * @param file the image file
     */
    private void showImage(@NonNull File file) {
        if (ConfigUtils.isDisplayableAnimatedImageFormat(getMessageModel().getFileData().getMimeType())) {
            Glide.with(this)
                .load(file)
                .optionalFitCenter()
                .error(R.drawable.ic_baseline_broken_image_200)
                .addListener(new RequestListener<>() {
                    @Override
                    public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
                        imageViewReference.get().setVisibility(View.GONE);
                        return true;
                    }

                    @Override
                    public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
                        imageViewReference.get().setVisibility(View.GONE);
                        return false;
                    }
                })
                .skipMemoryCache(true)
                .into(previewViewReference.get());
        } else {
            imageViewReference.get().setImage(ImageSource.uri(file.getPath()));
            imageViewReference.get().setVisibility(View.VISIBLE);

            BitmapUtil.ExifOrientation exifOrientation = BitmapUtil.getExifOrientation(requireContext(), Uri.fromFile(file));
            logger.debug("Orientation = {}", exifOrientation);
            int rotation = (int) exifOrientation.getRotation();

            if (exifOrientation.getFlip() != BitmapUtil.FLIP_NONE) {
                if ((exifOrientation.getFlip() & BitmapUtil.FLIP_VERTICAL) == BitmapUtil.FLIP_VERTICAL) {
                    imageViewReference.get().setScaleY(-1f);
                }
                if ((exifOrientation.getFlip() & BitmapUtil.FLIP_HORIZONTAL) == BitmapUtil.FLIP_HORIZONTAL) {
                    imageViewReference.get().setScaleX(-1f);
                    // invert rotation to compensate for flip
                    rotation = 360 - rotation;
                }
            }
            if (exifOrientation.getRotation() != 0F) {
                imageViewReference.get().setOrientation(rotation);
            }
        }
    }
}
