package com.ar.artraceartpro.ui.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.util.Log;
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.ar.artraceartpro.topon.AdManager;
import com.ar.artraceartpro.topon.onActionListener;
import com.google.common.util.concurrent.ListenableFuture;
import com.ar.artraceartpro.R;
import com.ar.artraceartpro.databinding.ActivityCameraBinding;
import com.ar.artraceartpro.utils.PermissionUtils;
import com.ar.artraceartpro.utils.TracingUtils;

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 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 Bitmap bitmap;
    private boolean isFlash = false;
    private Camera camera;
    private ImageCapture imageCapture;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityCameraBinding.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("imagePath");
        if (imagePath == null) {
            finish();
            return;
        }

        AdManager.loadAllAd();

        TracingUtils.displayImage(imagePath, binding.image, this, bitmap, this);
    }

    private void initEvent() {

        binding.image.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.flash.setOnClickListener(v -> toggleFlash());
        binding.back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        binding.camera.setOnClickListener(v -> takePhoto());
        binding.image.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 are denied. Please go to Settings and enable the permissions.", 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 go to Settings and enable it.", 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 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.image.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();
            TracingUtils.onInitIm(this, binding.image, width, height);
        }

    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        binding.image.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;

        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 = TracingUtils.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 = TracingUtils.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 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();
            isFlash = !isFlash;
            cameraControl.enableTorch(isFlash);
            binding.flash.setImageResource(isFlash ? R.drawable.flash : R.drawable.un_flash);
        }
    }

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