package com.ar.arsketch.activity;

import android.Manifest;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraControl;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.ar.arsketch.R;
import com.ar.arsketch.databinding.ActivityCameraBinding;
import com.ar.arsketch.topon.AdManager;
import com.ar.arsketch.topon.onActionListener;
import com.ar.arsketch.utils.PermissionUtils;
import com.ar.arsketch.utils.Tracing;
import com.google.common.util.concurrent.ListenableFuture;


import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ExecutionException;

public class CameraActivity extends AppCompatActivity implements View.OnTouchListener, SeekBar.OnSeekBarChangeListener {

    private static final int CAMERA_PERMISSION_REQUEST_CODE = 200;
    private static final int STORAGE_PERMISSION_REQUEST_CODE = 201;
    private static final int PICK_IMAGE_REQUEST_CODE = 202;

    private ActivityCameraBinding binding;

    private Matrix matrix = new Matrix();
    private Matrix savedMatrix = new Matrix();
    private PointF startPointF = new PointF();
    private float initialDistance;
    private int mode = MODE_NONE;
    private static final int MODE_NONE = 0;
    private static final int MODE_DRAG = 1;
    private static final int MODE_ZOOM = 2;

    private Bitmap bitmap;
    private boolean isFlashOn = false;
    private boolean isReOn = false;
    private Camera camera;
    private ImageCapture imageCapture;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityCameraBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        AdManager.loadAllAd();

        initData();
        initEvent();

    }

    private void initData() {

        String imagePath = getIntent().getStringExtra("imagePath");
        Log.d("image path", "image path: " + imagePath);
        if (imagePath != null) {
            displayImage(imagePath);
        }

    }

    private void initEvent() {

        binding.imageFull.setOnTouchListener(this);

        setupListeners();
        checkPermissionsAndStartCamera();
    }

    private void setupListeners() {
        binding.seekbar.setOnSeekBarChangeListener(this);
        binding.importImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AdManager.showTopOn(CameraActivity.this, new onActionListener() {
                    @Override
                    public void onAction() {
                        openImagePicker();
                    }
                });
            }
        });
        binding.light.setOnClickListener(v -> toggleFlash());
        binding.back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AdManager.showTopOn(CameraActivity.this, new onActionListener() {
                    @Override
                    public void onAction() {
                        finish();
                    }
                });
            }
        });
        binding.reversal.setOnClickListener(v -> toggleMirrorEffect());
        binding.play.setOnClickListener(v -> takePhoto());
        binding.imageFull.setOnTouchListener(this);
    }

    private void checkPermissionsAndStartCamera() {
        String[] permissions = getRequiredPermissions();
        if (PermissionUtils.hasPermissions(this, permissions)) {
            startCamera();
        } else {
            PermissionUtils.requestPermissions(this, permissions, CAMERA_PERMISSION_REQUEST_CODE);
        }
    }

    private void startCamera() {
        ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);
        cameraProviderFuture.addListener(() -> {
            try {
                ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
                bindPreview(cameraProvider);
                Preview preview = new Preview.Builder().build();
                preview.setSurfaceProvider(binding.preview.getSurfaceProvider());

                imageCapture = new ImageCapture.Builder().build();

                CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;

                cameraProvider.unbindAll();
                cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture);

            } catch (ExecutionException | InterruptedException e) {
                e.printStackTrace();
            }
        }, ContextCompat.getMainExecutor(this));
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) {
            if (PermissionUtils.handlePermissionsResult(grantResults)) {
                startCamera();
            } else {
                Toast.makeText(this, "Camera permissions denied, please enable permissions in Settings", Toast.LENGTH_SHORT).show();
            }
        } else if (requestCode == STORAGE_PERMISSION_REQUEST_CODE) {
            if (PermissionUtils.handlePermissionsResult(grantResults)) {
                openImagePicker();
            } else {
                Toast.makeText(this, "Storage permission is denied. Please enable the permission in the Settings", Toast.LENGTH_SHORT).show();
            }
        }
    }

    private void takePhoto() {
        if (imageCapture == null) {
            Toast.makeText(this, "The photo function is not initialized", Toast.LENGTH_SHORT).show();
            return;
        }

        ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "photo_" + System.currentTimeMillis() + ".jpg");
        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
        contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);

        ImageCapture.OutputFileOptions outputOptions = new ImageCapture.OutputFileOptions.Builder(
                getContentResolver(),
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                contentValues
        ).build();

        imageCapture.takePicture(
                outputOptions,
                ContextCompat.getMainExecutor(this),
                new ImageCapture.OnImageSavedCallback() {
                    @Override
                    public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                        Toast.makeText(CameraActivity.this, "The photo has been saved to the album", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onError(@NonNull ImageCaptureException exception) {
                        Toast.makeText(CameraActivity.this, "Photo failure: " + exception.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                }
        );
    }

    private void toggleMirrorEffect() {
        float scaleX = binding.imageFull.getScaleX();
        binding.imageFull.setScaleX(scaleX * -1);
        isReOn = !isReOn;
        binding.reversal.setImageResource(isReOn ? R.drawable.reversal : R.drawable.un_reversal);
    }

    private String[] getRequiredPermissions() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            return new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES};
        } else {
            return new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
        }
    }

    private void toggleFlash() {
        if (camera != null) {
            CameraControl cameraControl = camera.getCameraControl();
            isFlashOn = !isFlashOn;
            cameraControl.enableTorch(isFlashOn);
            binding.light.setImageResource(isFlashOn ? R.drawable.light : R.drawable.un_light);
        }
    }

    private void openImagePicker() {
        String[] permissions = PermissionUtils.getStoragePermissions();
        if (ContextCompat.checkSelfPermission(this, permissions[0]) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, permissions, STORAGE_PERMISSION_REQUEST_CODE);
        } else {
            Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            startActivityForResult(intent, PICK_IMAGE_REQUEST_CODE);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PICK_IMAGE_REQUEST_CODE && resultCode == RESULT_OK && data != null) {
            Uri selectedImageUri = data.getData();
            if (selectedImageUri != null) {
                binding.imageFull.setImageURI(selectedImageUri);
            }
        }
    }

    private void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
        Preview preview = new Preview.Builder().build();
        CameraSelector cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build();
        preview.setSurfaceProvider(binding.preview.getSurfaceProvider());
        cameraProvider.unbindAll();
        camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview);

        if (bitmap != null) {
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
            onInitIm(width, height);
        }

    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        binding.imageFull.setAlpha((100 - progress) / 100f);
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
    }

    private void displayImage(String imagePath) {
        if (imagePath.startsWith("/data/user/")) {
            displayImageFromStorage(imagePath);
        } else {
            displayImageFromAssets(imagePath);
        }

    }

    private void displayImageFromStorage(String imagePath) {
        Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
        if (bitmap != null) {
            binding.imageFull.setImageBitmap(bitmap);
        } else {
            Toast.makeText(this, "Image loading failed", Toast.LENGTH_SHORT).show();
        }
    }

    private void displayImageFromAssets(String imagePath) {
        try {
            AssetManager assetManager = getAssets();
            InputStream inputStream = assetManager.open(imagePath);
            bitmap = BitmapFactory.decodeStream(inputStream);
            binding.imageFull.setImageBitmap(bitmap);
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(this, "Image loading failed: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        ImageView view = (ImageView) v;

        Log.d("----", "--------a=" + event);
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                savedMatrix.set(matrix);
                startPointF.set(event.getX(), event.getY());
                mode = MODE_DRAG;
                break;

            case MotionEvent.ACTION_POINTER_DOWN:
                initialDistance = Tracing.getDistance(event);
                if (initialDistance > 10f) {
                    savedMatrix.set(matrix);
                    mode = MODE_ZOOM;
                }
                break;

            case MotionEvent.ACTION_MOVE:
                if (mode == MODE_DRAG) {
                    matrix.set(savedMatrix);
                    matrix.postTranslate(event.getX() - startPointF.x, event.getY() - startPointF.y);
                } else if (mode == MODE_ZOOM) {
                    float newDistance = Tracing.getDistance(event);
                    if (newDistance > 10f) {
                        float scale = newDistance / initialDistance;
                        matrix.set(savedMatrix);
                        matrix.postScale(scale, scale, view.getWidth() / 2f, view.getHeight() / 2f);
                    }
                }
                break;

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                mode = MODE_NONE;
                break;
        }

        view.setImageMatrix(matrix);
        return true;
    }

    private void onInitIm(float imW, float imH) {
        Point screen = getScreen();
        float newX = screen.x / 2f - imW / 2;
        float newY = screen.y / 2f - imH / 2;
        matrix.postTranslate(newX, newY);
        binding.imageFull.setImageMatrix(matrix);

        Log.d("---------------tt", "------startMatrix-----x=" + newX + "------y=" + newY);
    }

    public Point getScreen() {
        DisplayMetrics displayMetrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        int width = displayMetrics.widthPixels;
        int height = displayMetrics.heightPixels;
        Point point = new Point();
        point.x = width;
        point.y = height;
        return point;
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        AdManager.showTopOn(this, new onActionListener() {
            @Override
            public void onAction() {
                finish();
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        binding = null;
    }
}
