package com.kfzs.duanduan;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.app.ActivityCompat;
import android.text.TextUtils;
import android.widget.ImageView;

import com.flipboard.bottomsheet.BottomSheetLayout;
import com.flipboard.bottomsheet.commons.ImagePickerSheetView;

import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * <pre>
 *     sinlov
 *
 *     /\__/\
 *    /`    '\
 *  ≈≈≈ 0  0 ≈≈≈ Hello world!
 *    \  --  /
 *   /        \
 *  /          \
 * |            |
 *  \  ||  ||  /
 *   \_oo__oo_/≡≡≡≡≡≡≡≡o
 *
 * </pre>
 * Created by sinlov on 17/3/30.
 */
public abstract class PicBottomSheetActivity extends BaseCompatActivity {

    private static final int REQUEST_STORAGE = 9525;
    private static final int REQUEST_IMAGE_CAPTURE = REQUEST_STORAGE + 1;
    private static final int REQUEST_LOAD_IMAGE = REQUEST_IMAGE_CAPTURE + 1;

    private static int what;
    protected static PicBottomSheetHandler picBottomSheetHandler;

    protected BottomSheetLayout bottomSheetLayout;
    private Uri callBackImageUri = null;
    private String chooseTitleString;

//    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
//    @Override
//    public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
//        super.onCreate(savedInstanceState, persistentState);
//    }

    protected void initPicBottomSheetHandler() {
        picBottomSheetHandler = new PicBottomSheetHandler(this);
    }

    protected void initBottomSheetLayoutByID(@IdRes int bottomSheetID, @StringRes int titleStringID) {
        bottomSheetLayout = findViewById(bottomSheetID);
        chooseTitleString = getString(titleStringID);
        if (bottomSheetLayout != null || !TextUtils.isEmpty(chooseTitleString)) {
            bottomSheetLayout.setPeekOnDismiss(true);
        } else {
            throw new IllegalArgumentException("in this activity you are not use right ID" +
                    " at setting initBottomSheetLayoutByID(id)!");
        }
    }

    protected abstract boolean showSheetImageView(ImageView imageView, Uri imageUri, int size);

    protected abstract void callBackSelectedImageUriByBottomSheet(Uri selectedImageUri);


    /**
     * You can send message for {@link #safeHandleCallBack(WeakReference, int, Object)}
     *
     * @param what int
     * @param obj  object
     */
    protected void sendSafeHandle(int what, Object obj) {
        setInstanceWhat(what);
        picBottomSheetHandler.obtainMessage(what, obj).sendToTarget();
    }

    /**
     * you can use this tCallBack to do safe handler things by method {@link #sendSafeHandle(int, Object)}
     *
     * @param wrAct WeakReference
     * @param what  int
     * @param obj   object
     */
    public abstract void safeHandleCallBack(WeakReference<PicBottomSheetActivity> wrAct, int what, Object obj);

    protected boolean callSheetImageViewPop() {
        boolean needsPermission = checkNeedsPermission();
        if (needsPermission) {
            requestStoragePermission();
        } else {
            showSheetView();
        }
        return needsPermission;
    }

    protected static void setWhat(int what) {
        PicBottomSheetActivity.what = what;
    }


    public static class PicBottomSheetHandler extends Handler {

        private static WeakReference<PicBottomSheetActivity> wrActivity;

        /**
         * set target Activity to Weak reference and the customize handler be recycle timely.
         *
         * @param wrActivity WeakActivity
         */
        public PicBottomSheetHandler(PicBottomSheetActivity wrActivity) {
            PicBottomSheetHandler.wrActivity = new WeakReference<PicBottomSheetActivity>(wrActivity);
        }

        public WeakReference<PicBottomSheetActivity> get() {
            return wrActivity;
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            PicBottomSheetActivity ba = wrActivity.get();
            Object obj = msg.obj;
            if (null != ba && null != obj) {
                ba.safeHandleCallBack(wrActivity, what, obj);
            }
        }
    }

    private void setInstanceWhat(int what) {
        setWhat(what);
    }


    private boolean checkNeedsPermission() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && ActivityCompat.checkSelfPermission(PicBottomSheetActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void requestStoragePermission() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE);
        } else {
            // Eh, prompt anyway
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE);
        }
    }

    @TargetApi(Build.VERSION_CODES.M)
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == REQUEST_STORAGE) {
            if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                showSheetView();
            } else {
                // Permission denied
                showToast("Sheet is useless without access to external storage : ");
            }
        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    /**
     * Show an {@link ImagePickerSheetView}
     */
    private void showSheetView() {
        ImagePickerSheetView sheetView = new ImagePickerSheetView.Builder(this)
                .setMaxItems(30)
                .setShowCameraOption(createCameraIntent() != null)
                .setShowPickerOption(createPickIntent() != null)
                .setImageProvider(new ImagePickerSheetView.ImageProvider() {
                    @Override
                    public void onProvideImage(ImageView imageView, Uri imageUri, int size) {
                        boolean isSetting = showSheetImageView(imageView, imageUri, size);
                        if (!isSetting) {
                            throw new IllegalArgumentException("you are not use showSheetImageView() and return true!");
                        }
                    }
                })
                .setOnTileSelectedListener(new ImagePickerSheetView.OnTileSelectedListener() {
                    @Override
                    public void onTileSelected(ImagePickerSheetView.ImagePickerTile selectedTile) {
                        bottomSheetLayout.dismissSheet();
                        if (selectedTile.isCameraTile()) {
                            dispatchTakePictureIntent();
                        } else if (selectedTile.isPickerTile()) {
                            startActivityForResult(createPickIntent(), REQUEST_LOAD_IMAGE);
                        } else if (selectedTile.isImageTile()) {
                            callBackSelectedImageUriByBottomSheet(selectedTile.getImageUri());
                        } else {
                            genericError();
                        }
                    }
                })
                .setTitle(chooseTitleString)
                .create();
        if (bottomSheetLayout != null) {
            bottomSheetLayout.showWithSheetView(sheetView);
        } else {
            throw new IllegalArgumentException("in this activity you are not setting initBottomSheetLayoutByID(id) at Layout!");
        }
    }

    /**
     * For images captured from the camera, we need to create a File first to tell the camera
     * where to store the image.
     *
     * @return the File created for the image to be store under.
     */
    private File createImageFile() throws IOException {
        // Create an image file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        File imageFile = File.createTempFile(
                imageFileName,  /* prefix */
                ".jpg",         /* suffix */
                storageDir      /* directory */
        );

        // Save a file: path for use with ACTION_VIEW intents
        callBackImageUri = Uri.fromFile(imageFile);
        return imageFile;
    }

    /**
     * This checks to see if there is a suitable activity to handle the `ACTION_PICK` intent
     * and returns it if found. {@link Intent#ACTION_PICK} is for picking an image from an external app.
     *
     * @return A prepared intent if found.
     */
    @Nullable
    private Intent createPickIntent() {
        Intent picImageIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        if (picImageIntent.resolveActivity(getPackageManager()) != null) {
            return picImageIntent;
        } else {
            return null;
        }
    }

    /**
     * This checks to see if there is a suitable activity to handle the {@link MediaStore#ACTION_IMAGE_CAPTURE}
     * intent and returns it if found. {@link MediaStore#ACTION_IMAGE_CAPTURE} is for letting another app take
     * a picture from the camera and store it in a file that we specify.
     *
     * @return A prepared intent if found.
     */
    @Nullable
    private Intent createCameraIntent() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
            return takePictureIntent;
        } else {
            return null;
        }
    }

    /**
     * This utility function combines the camera intent creation and image file creation, and
     * ultimately fires the intent.
     *
     * @see {@link #createCameraIntent()}
     * @see {@link #createImageFile()}
     */
    private void dispatchTakePictureIntent() {
        Intent takePictureIntent = createCameraIntent();
        // Ensure that there's a camera activity to handle the intent
        if (takePictureIntent != null) {
            // Create the File where the photo should go
            try {
                File imageFile = createImageFile();
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imageFile));
                startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
            } catch (IOException e) {
                // Error occurred while creating the File
                genericError("Could not create imageFile for camera");
            }
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            Uri selectedImage = null;
            if (requestCode == REQUEST_LOAD_IMAGE && data != null) {
                selectedImage = data.getData();
                if (selectedImage == null) {
                    genericError();
                }
            } else if (requestCode == REQUEST_IMAGE_CAPTURE) {
                // Do something with imagePath
                selectedImage = callBackImageUri;
            }

            if (selectedImage != null) {
                callBackSelectedImageUriByBottomSheet(selectedImage);
            } else {
                genericError();
            }
        }
    }

    private void genericError() {
        genericError(null);
    }

    private void genericError(String message) {
        showToast(message == null ? "Something went wrong." : message);
    }
}
