package com.ar.ardrawingboard.ui.fragment;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.LiveData;
import androidx.recyclerview.widget.GridLayoutManager;

import com.ar.ardrawingboard.databinding.FragmentImportBinding;
import com.ar.ardrawingboard.room.AppDatabase;
import com.ar.ardrawingboard.room.BoardEntry;
import com.ar.ardrawingboard.room.BoardEntryDao;
import com.ar.ardrawingboard.ui.adapter.ImportFragmentAdapter;
import com.ar.ardrawingboard.util.ItemDecoration;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class ImportFragment extends Fragment implements ImportFragmentAdapter.OnHeaderClickListener {
    private FragmentImportBinding uiBinding;
    private ImportFragmentAdapter imageAdapter;
    private final List<String> storedImagePaths = new ArrayList<>();
    private BoardEntryDao databaseDao;
    private static final int MAX_IMAGE_SIZE_BYTES = 10 * 1024 * 1024;

    private final ActivityResultLauncher<Intent> imagePickerLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            result -> {
                if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
                    Uri imageUri = result.getData().getData();
                    if (imageUri != null) {
                        processSelectedImage(imageUri);
                    }
                }
            });

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        uiBinding = FragmentImportBinding.inflate(inflater, container, false);
        initializeRecyclerView();
        setupDatabase();
        observeImageData();
        return uiBinding.getRoot();
    }

    private void initializeRecyclerView() {
        uiBinding.recyclerview.setLayoutManager(new GridLayoutManager(requireContext(), 2));
        uiBinding.recyclerview.addItemDecoration(new ItemDecoration(16, 19, 10));
        imageAdapter = new ImportFragmentAdapter(new ArrayList<>(), requireActivity(), this);
        uiBinding.recyclerview.setAdapter(imageAdapter);
    }

    private void setupDatabase() {
        AppDatabase database = AppDatabase.getInstance(requireContext());
        databaseDao = database.boardEntryDao();
    }

    private void observeImageData() {
        LiveData<List<BoardEntry>> imageLiveData = databaseDao.getImportLive();
        imageLiveData.observe(getViewLifecycleOwner(), entries -> imageAdapter.refreshItems(entries));
    }

    @Override
    public void onResume() {
        super.onResume();
        imageAdapter.notifyDataSetChanged();
    }

    @Override
    public void onHeaderClick() {
        launchImagePicker();
    }

    private void launchImagePicker() {
        Intent pickIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        imagePickerLauncher.launch(pickIntent);
    }

    private void processSelectedImage(Uri imageUri) {
        try {
            if (isImageSizeValid(imageUri)) {
                storeImageLocally(imageUri);
            } else {
                Toast.makeText(requireContext(), "Image exceeds size limit", Toast.LENGTH_SHORT).show();
            }
        } catch (IOException e) {
            Toast.makeText(requireContext(), "Error checking image: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    private boolean isImageSizeValid(Uri uri) throws IOException {
        try (InputStream stream = requireContext().getContentResolver().openInputStream(uri)) {
            if (stream == null) return false;
            return stream.available() <= MAX_IMAGE_SIZE_BYTES;
        }
    }

    private void storeImageLocally(Uri uri) {
        try {
            InputStream inputStream = requireContext().getContentResolver().openInputStream(uri);
            Bitmap imageBitmap = BitmapFactory.decodeStream(inputStream);
            if (imageBitmap == null) {
                Toast.makeText(requireContext(), "Failed to load image", Toast.LENGTH_SHORT).show();
                return;
            }

            File storageDir = requireContext().getFilesDir();
            File newImageFile = new File(storageDir, System.currentTimeMillis() + ".jpg");
            try (FileOutputStream outputStream = new FileOutputStream(newImageFile)) {
                imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
            }
            if (inputStream != null) {
                inputStream.close();
            }

            String newImagePath = newImageFile.getAbsolutePath();
            saveImageToDatabase(newImagePath, newImageFile);

        } catch (IOException e) {
            Toast.makeText(requireContext(), "Error saving image: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    private void saveImageToDatabase(String imagePath, File imageFile) {
        new Thread(() -> {
            if (isDuplicateImage(imagePath)) {
                requireActivity().runOnUiThread(() ->
                        Toast.makeText(requireContext(), "Image already exists", Toast.LENGTH_SHORT).show());
                imageFile.delete();
                return;
            }
            storedImagePaths.add(imagePath);
            databaseDao.insert(new BoardEntry(false, true, imagePath));
        }).start();
    }

    private boolean isDuplicateImage(String newImagePath) {
        File newFile = new File(newImagePath);
        for (String existingPath : storedImagePaths) {
            if (areFilesEqual(new File(existingPath), newFile)) {
                return true;
            }
        }
        List<BoardEntry> entries = databaseDao.getImport();
        for (BoardEntry entry : entries) {
            if (areFilesEqual(new File(entry.getPath()), newFile)) {
                return true;
            }
        }
        return false;
    }

    private boolean areFilesEqual(File file1, File file2) {
        return file1.length() == file2.length();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        uiBinding = null;
    }
}