package com.example.tp8;

import android.Manifest;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
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 androidx.exifinterface.media.ExifInterface;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

public class PhotoListActivity extends AppCompatActivity {

    private static final int PERMISSIONS_REQUEST_READ_IMAGES = 100; // ID de la requête de permission

    private PhotoAdapter adapter;
    private double[] referenceLatLong;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_photo_list);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.photo_list_layout), (v, insets) -> { // Changed R.id.main to R.id.photo_list_layout
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        referenceLatLong = getIntent().getDoubleArrayExtra("referenceLatLong"); // Je récupère la valeur de référence pour la position GPS
        if (referenceLatLong == null) {
            finish(); // Ne devrait pas se produire normalement
            return;
        }

        RecyclerView recyclerView = findViewById(R.id.photo_recycler_view); // https://developer.android.com/develop/ui/views/layout/recyclerview?hl=fr
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        adapter = new PhotoAdapter(); // Affichage d'une liste dynamique de photos
        recyclerView.setAdapter(adapter);

        checkPermissionAndLoadPhotos(); // Vérification des permissions, puis chargement des photos
    }

    private void checkPermissionAndLoadPhotos() {
        List<String> permissionsToRequest = new ArrayList<>();

        // Choisir la permission de stockage appropriée
        String storagePermission;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // If-else recommandé par Android Studio pour gérer toutes les versions d'Android
            storagePermission = Manifest.permission.READ_MEDIA_IMAGES; // https://developer.android.com/about/versions/14/changes/partial-photo-video-access?hl=fr
        } else {
            storagePermission = Manifest.permission.READ_EXTERNAL_STORAGE;
        }

        if (ContextCompat.checkSelfPermission(this, storagePermission) != PackageManager.PERMISSION_GRANTED) {
            permissionsToRequest.add(storagePermission); // Je n'ai pas la permission, j'ajoute à la liste de perms à demander
        }

        // Ajouter la permission pour la localisation des médias, pour lire les métadonnées des images
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_MEDIA_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            permissionsToRequest.add(Manifest.permission.ACCESS_MEDIA_LOCATION); // J'ajoute aussi si je ne l'ai pas
        }

        if (!permissionsToRequest.isEmpty()) {
            // Demander les permissions nécessaires
            ActivityCompat.requestPermissions(this, permissionsToRequest.toArray(new String[0]), PERMISSIONS_REQUEST_READ_IMAGES);
        } else {
            // OK, toutes les permissions sont déjà accordées
            loadPhotos();
        }
    }

    @Override // Fonction appelée quand le système a reçu une réponse de la demande de permission
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == PERMISSIONS_REQUEST_READ_IMAGES) {
            // Vérifier si toutes les permissions demandées ont été accordées
            boolean allGranted = true;
            for (int grantResult : grantResults) {
                if (grantResult != PackageManager.PERMISSION_GRANTED) {
                    allGranted = false;
                    break;
                }
            }

            if (allGranted) {
                // Permissions OK
                loadPhotos();
            } else {
                // Au moins une permission a été refusée
                Toast.makeText(this, getText(R.string.missing_permission), Toast.LENGTH_LONG).show();
                finish(); // Terminer ici
            }
        }
    }

    // Fonction de chargement des photos
    private void loadPhotos() {
        new Thread(() -> { // Dans un thread, comme vu dans la doc' Android
            List<PhotoItem> photoItems = new ArrayList<>(); // Liste principale des images
            ContentResolver contentResolver = getContentResolver();
            Uri queryUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; // Champ recherché
            String[] projection = {MediaStore.Images.Media._ID};

            try (Cursor cursor = contentResolver.query(queryUri, projection, null, null, MediaStore.Images.Media.DATE_ADDED + " DESC")) { // Je tente de prioriser les images récentes
                if (cursor != null) {
                    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID); // ID colone rechercheé
                    while (cursor.moveToNext()) { // Tant qu'il y a des images
                        long id = cursor.getLong(idColumn);
                        Uri photoUri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, Long.toString(id)); // Récupérer l'URI

                        try (InputStream inputStream = contentResolver.openInputStream(photoUri)) { // Je tente d'avoir l'InputStream
                            if (inputStream != null) {
                                ExifInterface exifInterface = new ExifInterface(inputStream); // Que je convertis en ExifInterface
                                double[] latLong = exifInterface.getLatLong();
                                if (latLong != null) {
                                    double distance = distance(referenceLatLong[0], referenceLatLong[1], latLong[0], latLong[1]); // D'où je récupère la distance
                                    photoItems.add(new PhotoItem(photoUri, distance)); // Et j'ajoute ça à la liste
                                }
                            }
                        } catch (IOException e) {
                            // J'ignore les images impossibles à lire, possiblement corrompues
                        } catch (Exception e) {
                            // Juste au cas où, je collecte ici tout le reste pour le débug
                            e.printStackTrace();
                        }
                    }
                }
            }

            Collections.sort(photoItems); // Je lance un tri sur la liste de photos (méthode de tri sur la distance)
            runOnUiThread(() -> {
                if (photoItems.isEmpty()) { // Message s'il n'y a pas de photos
                    Toast.makeText(PhotoListActivity.this, getString(R.string.no_pictures_found), Toast.LENGTH_LONG).show();
                }
                adapter.submitList(photoItems);// Puis envoi de la liste
            });
        }).start();
    }

    // J'aurai aussi pu passer par https://developer.android.com/reference/android/location/Location#distanceBetween(double,%20double,%20double,%20double,%20float[])
    private static double distance(double lat1, double lon1, double lat2, double lon2) {
        double R = 6371; // Rayon de la Terre, utilisé pour https://fr.wikipedia.org/wiki/Formule_de_haversine
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
                        Math.sin(dLon / 2) * Math.sin(dLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return R * c;
    }

    private static class PhotoItem implements Comparable<PhotoItem> {
        final Uri uri;
        final double distance;

        PhotoItem(Uri uri, double distance) {
            this.uri = uri;
            this.distance = distance;
        }

        @Override
        public int compareTo(PhotoItem other) {
            return Double.compare(this.distance, other.distance);
        }
    }


    // Classe que je garde là pour gérer proprement les photos
    private static class PhotoAdapter extends ListAdapter<PhotoItem, PhotoAdapter.PhotoViewHolder> {
    // https://developer.android.com/reference/androidx/recyclerview/widget/ListAdapter
        protected PhotoAdapter() {
            super(DIFF_CALLBACK); // utilisé par Android pour savoir s'il faut rebuild la liste
        }

        @NonNull
        @Override // Afficher les images à la création du widget
        public PhotoAdapter.PhotoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_photo, parent, false);
            return new PhotoAdapter.PhotoViewHolder(view);
        }

        @Override
        public void onBindViewHolder(@NonNull PhotoAdapter.PhotoViewHolder holder, int position) {
            PhotoItem item = getItem(position);
            holder.bind(item);
        }

        static class PhotoViewHolder extends RecyclerView.ViewHolder {
            // La sous-classe qui gère quelques méthodes d'affichage des images
            final ImageView thumbnail;
            final TextView distance;

            PhotoViewHolder(@NonNull View itemView) {
                super(itemView);
                thumbnail = itemView.findViewById(R.id.photo_thumbnail);
                distance = itemView.findViewById(R.id.photo_distance);
            }

            void bind(PhotoItem item) {
                thumbnail.setImageURI(item.uri); // Image affichée
                distance.setText(String.format(Locale.getDefault(), "Distance: %.2f km", item.distance)); // Texte
            }
        }

        private static final DiffUtil.ItemCallback<PhotoItem> DIFF_CALLBACK = // Android se sert de cette partie pour comparer les éléments https://developer.android.com/reference/androidx/leanback/widget/DiffCallback
                new DiffUtil.ItemCallback<PhotoItem>() {
                    @Override
                    public boolean areItemsTheSame(@NonNull PhotoItem oldItem, @NonNull PhotoItem newItem) {
                        return oldItem.uri.equals(newItem.uri);
                    }

                    @Override
                    public boolean areContentsTheSame(@NonNull PhotoItem oldItem, @NonNull PhotoItem newItem) {
                        return oldItem.distance == newItem.distance;
                    }
                };
    }

}