package com.example.epl498_labs.ui.sensors;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.camera.core.Camera;
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.camera.view.PreviewView;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.LifecycleOwner;
import androidx.navigation.fragment.NavHostFragment;

import com.example.epl498_labs.R;
import com.google.common.util.concurrent.ListenableFuture;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.concurrent.ExecutionException;

public class CameraFragment extends Fragment {

    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
    private ImageCapture imageCapture;
    private PreviewView previewView;
    private Camera camera;

    // Define the permissions you want to request
    private static final String[] REQUIRED_PERMISSIONS = {
            Manifest.permission.CAMERA,
            Manifest.permission.READ_MEDIA_IMAGES
    };

    // Request code for permission launcher
    private final ActivityResultLauncher<String[]> requestPermissionLauncher =
            registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), permissions -> {
                boolean allPermissionsGranted = true;
                for (Boolean permission : permissions.values()) {
                    if (!permission) {
                        allPermissionsGranted = false;
                        break;
                    }
                }

                if (allPermissionsGranted) {
                    // All permissions are granted, you can start the camera
                    startCamera();
                } else {
                    // Permission(s) denied, handle accordingly (e.g., show a message)
                    Toast.makeText(requireContext(), "Permissions not granted.", Toast.LENGTH_SHORT).show();
                    requireActivity().finish();
                }
            });

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_camera, container, false);
        previewView = view.findViewById(R.id.preview_view);
        Button captureButton = view.findViewById(R.id.capture_button);
        Button photoListButton = view.findViewById(R.id.photo_list_button);

        // Set a click listener for the "Photos" button to navigate to the PhotoListFragment
        photoListButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                NavHostFragment.findNavController(CameraFragment.this)
                        .navigate(R.id.action_CameraFragment_to_PhotoListFragment);
            }
        });

        // Set a click listener for the "Capture" button to take a photo
        captureButton.setOnClickListener(v -> capturePhoto());

        // Request camera permissions
        requestCameraPermission();

        return view;
    }

    // Request camera permissions based on the REQUIRED_PERMISSIONS array
    private void requestCameraPermission() {
        if (allPermissionsGranted()) {
            startCamera();
        } else {
            requestPermissionLauncher.launch(REQUIRED_PERMISSIONS);
        }
    }

    // Initialize and start the camera
    private void startCamera() {
        cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext());
        cameraProviderFuture.addListener(() -> {
            try {
                ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
                bindCameraUseCases(cameraProvider);
            } catch (ExecutionException | InterruptedException e) {
                Log.e("CameraFragment", "Error initializing cameraProviderFuture: " + e.getMessage());
            }
        }, ContextCompat.getMainExecutor(requireContext()));
    }

    // Bind camera use cases such as preview and image capture
    private void bindCameraUseCases(ProcessCameraProvider cameraProvider) {
        CameraSelector cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build();

        Preview preview = new Preview.Builder().build();
        preview.setSurfaceProvider(previewView.getSurfaceProvider());

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

        // Unbind previous use cases (if any)
        if (camera != null) {
            cameraProvider.unbindAll();
        }

        // Bind the camera to the lifecycle and store it in the camera member variable
        camera = cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, preview, imageCapture);
    }

    // Check if all required permissions are granted
    private boolean allPermissionsGranted() {
        for (String permission : REQUIRED_PERMISSIONS) {
            if (ContextCompat.checkSelfPermission(requireContext(), permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    // Capture a photo and save it to the app's internal storage directory
    private void capturePhoto() {
        // Get the app's internal storage directory
        File internalStorageDir = requireContext().getFilesDir();

        if (internalStorageDir != null) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss", Locale.ENGLISH);
            String currentTime = sdf.format(System.currentTimeMillis());
            String fileName = currentTime + ".jpg";
            File outputFile = new File(internalStorageDir, fileName);

            ImageCapture.OutputFileOptions outputOptions = new ImageCapture.OutputFileOptions.Builder(outputFile).build();

            imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(requireContext()), new ImageCapture.OnImageSavedCallback() {
                @Override
                public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                    Toast.makeText(requireContext(), "Photo saved: " + outputFile.getAbsolutePath(), Toast.LENGTH_LONG).show();
                    Log.i("CameraFragment", "Photo saved: " + outputFile.getAbsolutePath());
                }

                @Override
                public void onError(@NonNull ImageCaptureException exception) {
                    Log.e("CameraFragment", "Photo capture failed: " + exception.getMessage());
                    // Handle the error, e.g., display an error message to the user.
                }
            });
        } else {
            // Handle the case where the app's internal storage directory is not available
            Toast.makeText(requireContext(), "Internal storage directory not available.", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        // Reinitialize the camera if it was released
        if (camera == null) {
            startCamera();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        releaseCamera(); // Release the camera resources when the fragment is destroyed
    }

    // Release camera resources
    private void releaseCamera() {
        if (cameraProviderFuture != null) {
            cameraProviderFuture.addListener(() -> {
                try {
                    ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
                    cameraProvider.unbindAll(); // Release the camera
                } catch (ExecutionException | InterruptedException e) {
                    Log.e("CameraFragment", "Error releasing camera: " + e.getMessage());
                }
            }, ContextCompat.getMainExecutor(requireContext()));
        }
    }
}
