package com.ardraw.ardrawinggallery.activity;

import android.Manifest;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Matrix;
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.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
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 androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import com.ardraw.ardrawinggallery.R;
import com.ardraw.ardrawinggallery.databinding.ActivityPaintBinding;
import com.ardraw.ardrawinggallery.util.ImageManager;
import com.ardraw.ardrawinggallery.util.PermissionsHelper;
import com.google.common.util.concurrent.ListenableFuture;

import java.util.concurrent.ExecutionException;

public class PaintActivity extends AppCompatActivity implements View.OnTouchListener, SeekBar.OnSeekBarChangeListener{
    private ActivityPaintBinding binding;

    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 final Matrix matrix = new Matrix();
    private final Matrix savedMatrix = new Matrix();
    private final 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 boolean isFlash = false;
    private Camera camera;
    private ImageCapture imageCapture;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityPaintBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        EdgeToEdge.enable(this);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        initData();
        initEvent();
    }

    private void initData() {
        String imagePath = getIntent().getStringExtra("WallpaperPath");
        if (imagePath == null) {
            finish();
            return;
        }

        ImageManager.loadImage(imagePath, binding.imageView, this, this);
    }

    private void initEvent() {
        binding.imageView.setOnTouchListener(this);

        setupListeners();
        checkPermissionsAndStartCamera();
    }

    private void setupListeners() {
        binding.seekbar.setOnSeekBarChangeListener(this);
        binding.photo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                openImagePicker();
            }
        });
        binding.flash.setOnClickListener(v -> toggleFlash());
        binding.back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        binding.camera.setOnClickListener(v -> takePhotoAndSave());
        binding.imageView.setOnTouchListener(this);
    }

    private void checkPermissionsAndStartCamera() {
        String[] permissions = getPermissions();
        if (PermissionsHelper.arePermissionsGranted(this, permissions)) {
            initiateCamera();
        } else {
            PermissionsHelper.requestUserPermissions(this, permissions, CAMERA_PERMISSION_REQUEST_CODE);
        }
    }

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

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

                CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;

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

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

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

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

        if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) {
            if (PermissionsHelper.wasPermissionsGranted(grantResults)) {
                initiateCamera();
            } else {
                Toast.makeText(this, "Camera permissions are denied. Please go to Settings and enable the permissions.", Toast.LENGTH_SHORT).show();
            }
        } else if (requestCode == STORAGE_PERMISSION_REQUEST_CODE) {
            if (PermissionsHelper.wasPermissionsGranted(grantResults)) {
                openImagePicker();
            } else {
                Toast.makeText(this, "Storage permission is denied. Please go to Settings and enable it.", Toast.LENGTH_SHORT).show();
            }
        }
    }

    private void takePhotoAndSave() {
        if (imageCapture == null) {
            Toast.makeText(this, "Camera is not initialized", Toast.LENGTH_SHORT).show();
            return;
        }

        if (!hasCameraPermissions()) {
            requestCameraPermissions();
            return;
        }

        ContentValues contentValues = prepareContentValues();

        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(PaintActivity.this, "Photo saved to album", Toast.LENGTH_SHORT).show();
                    }

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

    private boolean hasCameraPermissions() {
        return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
    }

    private void requestCameraPermissions() {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
    }

    private ContentValues prepareContentValues() {
        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);
        return contentValues;
    }


    private void openImagePicker() {
        String[] permissions = PermissionsHelper.getRequiredStoragePermissions();
        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.imageView.setImageURI(selectedImageUri);
            }
        }
    }

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

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
    }

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

        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 = ImageManager.calculateDistanceBetweenTouches(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 = ImageManager.calculateDistanceBetweenTouches(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 String[] getPermissions() {
        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();
            isFlash = !isFlash;
            cameraControl.enableTorch(isFlash);
            binding.flash.setImageResource(isFlash ? R.drawable.flash : R.drawable.un_flash);
        }
    }

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