package com.example.modifier.ui.backup

import android.content.Context
import android.content.DialogInterface
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.widget.doAfterTextChanged
import androidx.fragment.app.Fragment
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.asFlow
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.modifier.adapter.BackupAdapter
import com.example.modifier.baseTag
import com.example.modifier.data.AppDatabase
import com.example.modifier.data.BackupItem
import com.example.modifier.databinding.FragmentBackupBinding
import com.example.modifier.enums.ReqState
import com.example.modifier.repo.AppStateRepo
import com.example.modifier.repo.BackupRepository
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File

class BackupFragment : Fragment() {
    companion object {
        private const val TAG = "$baseTag/BackupFragment"
    }

    private lateinit var binding: FragmentBackupBinding
    private val list = mutableListOf<BackupItem>()
    private lateinit var adapter: BackupAdapter
    private lateinit var onItemClickListener: BackupAdapter.OnItemClickListener
    private val backupItemDao by lazy {
        AppDatabase.getDatabase(requireContext()).itemDao()
    }
    private val backupRepository by lazy {
        BackupRepository(requireContext(), backupItemDao)
    }
    private var sort: Boolean
        get() {
            return requireContext().getSharedPreferences("backup", Context.MODE_PRIVATE)
                .getBoolean("sort", false)
        }
        set(value) {
            requireContext().getSharedPreferences("backup", Context.MODE_PRIVATE).edit()
                .putBoolean("sort", value).apply()
        }
    private val searchText = MutableLiveData<String>()
    private lateinit var progressDialog: AlertDialog

    @OptIn(FlowPreview::class)
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        if (!this::binding.isInitialized) {
            progressDialog = MaterialAlertDialogBuilder(requireContext())
                .setTitle("Please wait...")
                .setMessage("Processing...")
                .setCancelable(false)
                .create()
            binding = FragmentBackupBinding.inflate(inflater, container, false)
            onItemClickListener = object : BackupAdapter.OnItemClickListener {
                override fun onRestoreClick(backup: BackupItem, position: Int) {
                    MaterialAlertDialogBuilder(requireContext())
                        .setTitle("Restore backup")
                        .setMessage("Are you sure you want to restore this backup?")
                        .setPositiveButton("Yes") { dialog: DialogInterface?, which: Int ->
                            dialog?.dismiss()
                            progressDialog.show()
                            CoroutineScope(Dispatchers.IO).launch {
                                AppStateRepo.instance.updateRuntimeFlags(reqState = ReqState.RESTORE)
                                try {
                                    backupRepository.restore(backup)
                                } catch (e: Exception) {
                                    e.printStackTrace()
                                }
                                AppStateRepo.instance.updateRuntimeFlags(reqState = ReqState.NONE)
                                withContext(Dispatchers.Main) {
                                    progressDialog.dismiss()
                                    Toast.makeText(
                                        requireContext(),
                                        "Restore completed",
                                        Toast.LENGTH_SHORT
                                    ).show()
                                }
                            }
                        }
                        .setNegativeButton("No", null)
                        .show()
                }

                override fun onDeleteClick(backup: BackupItem, position: Int) {
                    progressDialog.show()
                    CoroutineScope(Dispatchers.IO).launch {
                        val file = File(backup.path)
                        if (file.exists()) {
                            try {
                                File(backup.path).deleteRecursively()

                            } catch (e: Exception) {
                                e.printStackTrace()
                                Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
                            }
                        } else {
                            Log.e("BackupAdapter", "File not found")
                        }
                        list.remove(backup)
                        withContext(Dispatchers.Main) {
                            adapter.notifyDataSetChanged()
                        }
                        backupRepository.delete(backup)
                        withContext(Dispatchers.Main) {
                            progressDialog.dismiss()
                            Toast.makeText(
                                requireContext(),
                                "Backup deleted",
                                Toast.LENGTH_SHORT
                            ).show()
                        }
                    }
                }
            }
            adapter = BackupAdapter(requireContext(), list, onItemClickListener)
            binding.rvBackup.adapter = adapter
            binding.rvBackup.layoutManager = LinearLayoutManager(requireContext())
            binding.btnSort.setOnClickListener {
                sort = !sort
                lifecycleScope.launch {
                    withContext(Dispatchers.IO) {
                        refresh()
                    }
                }
            }
            binding.btnAdd.setOnClickListener {
                lifecycleScope.launch {
                    progressDialog.show()
                    withContext(Dispatchers.IO) {
                        val backup = backupRepository.backup(type = "manual", sendCount = 0)
                        if (backup != null) {
                            list.add(0, backup)
                        }
                    }
                    adapter.notifyItemInserted(0)
                    progressDialog.dismiss()
                    Toast.makeText(
                        requireContext(),
                        "Backup created",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            }
            binding.etSearch.doAfterTextChanged {
                searchText.postValue(it.toString())
            }
            ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
                binding.searchBar.setPadding(
                    binding.searchBar.paddingLeft,
                    insets.getInsets(WindowInsetsCompat.Type.systemBars()).top,
                    binding.searchBar.paddingRight,
                    binding.searchBar.paddingBottom,
                )
                insets
            }
        }
        lifecycleScope.launch {
            withContext(Dispatchers.IO) {
                refresh()
            }
        }
        lifecycleScope.launch {
            searchText.asFlow().debounce(500).collect {
                Log.i(TAG, "searchText: $it")
                refresh(it)
            }
        }
        return binding.root
    }

    private suspend fun refresh(number: String? = null) {
        val all = when (sort) {
            true -> {
                when (number) {
                    null -> backupItemDao.getAll()
                    else -> backupItemDao.getAll("%$number%")
                }
            }

            false -> {
                when (number) {
                    null -> backupItemDao.getAllR()
                    else -> backupItemDao.getAllR("%$number%")
                }
            }
        }
        list.clear()
        list.addAll(all)
        withContext(Dispatchers.Main) {
            adapter.notifyDataSetChanged()
        }
    }

}
