package com.rugvedsarika.voicereader.ui.home

import android.os.Bundle
import android.os.Environment
import android.text.Spannable
import android.text.SpannableString
import android.text.style.BackgroundColorSpan
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.app.Activity
import android.content.Intent
import android.view.animation.AnimationUtils
import android.widget.Toast

import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.core.widget.addTextChangedListener

import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import com.rugvedsarika.voicereader.OCRScannerActivity
import com.rugvedsarika.voicereader.R
import com.rugvedsarika.voicereader.databinding.FragmentHomeBinding
import com.rugvedsarika.voicereader.ui.MainViewModel
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

class HomeFragment : Fragment() {

    private var _binding: FragmentHomeBinding? = null
    private val binding get() = _binding!!

    private val viewModel: MainViewModel by activityViewModels()

    private val filePickerLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
        uri?.let { handleFileImport(it) }
    }

    private val ocrLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            val scanResult = result.data?.getStringExtra("SCAN_RESULT")
            scanResult?.let {
                binding.textToSpeak.setText(it)
                Toast.makeText(context, getString(R.string.msg_scanned), Toast.LENGTH_SHORT).show()
            }
        }
    }

    private val cameraPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
        if (isGranted) {
            startOCR()
        } else {
            Toast.makeText(context, "Camera permission required for OCR", Toast.LENGTH_SHORT).show()
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentHomeBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.textToSpeak.setText(viewModel.textToSpeak.value)
        binding.textToSpeak.addTextChangedListener {
            viewModel.textToSpeak.value = it.toString()
        }

        viewModel.textSize.observe(viewLifecycleOwner) { size ->
            binding.textToSpeak.textSize = size
        }

        binding.btnImportFile.setOnClickListener {
            filePickerLauncher.launch("*/*")
        }

        binding.btnImportWeb.setOnClickListener {
            showWebImportDialog()
        }

        binding.btnScan.setOnClickListener {
            checkCameraPermissionAndStartOCR()
        }

        binding.btnPlayPause.setOnClickListener { view ->
            view.performHapticFeedback(android.view.HapticFeedbackConstants.VIRTUAL_KEY)
            if (viewModel.isSpeaking.value == true) {
                viewModel.pause()
            } else {
                viewModel.speak()
            }
        }

        binding.btnStop.setOnClickListener {
            it.performHapticFeedback(android.view.HapticFeedbackConstants.VIRTUAL_KEY)
            viewModel.stop()
        }

        binding.btnTimer.setOnClickListener {
            showSleepTimerDialog()
        }

        binding.btnSave.setOnClickListener {
            saveAudio()
        }

        viewModel.isTtsReady.observe(viewLifecycleOwner) { ready ->
            binding.btnPlayPause.isEnabled = ready
            binding.btnSave.isEnabled = ready
        }

        viewModel.isSpeaking.observe(viewLifecycleOwner) { speaking ->
            binding.speechIndicator.visibility = if (speaking) View.VISIBLE else View.GONE
            updatePlayPauseButton(speaking, viewModel.isPaused.value ?: false)
            
            if (speaking) {
                binding.btnPlayPause.animate().scaleX(1.1f).scaleY(1.1f).setDuration(200).withEndAction {
                    binding.btnPlayPause.animate().scaleX(1.0f).scaleY(1.0f).setDuration(200).start()
                }.start()
            }
        }

        viewModel.isPaused.observe(viewLifecycleOwner) { paused ->
            updatePlayPauseButton(viewModel.isSpeaking.value ?: false, paused)
        }

        viewModel.wordRange.observe(viewLifecycleOwner) { range ->
            highlightText(range.first, range.second)
            autoScrollToText(range.first)
        }

        viewModel.sleepTimerActive.observe(viewLifecycleOwner) { active ->
            binding.tvTimerStatus.visibility = if (active) View.VISIBLE else View.GONE
        }

        viewModel.timerRemainingSeconds.observe(viewLifecycleOwner) { seconds ->
            if (seconds > 0) {
                binding.tvTimerStatus.visibility = View.VISIBLE
                val minutes = seconds / 60
                val secs = seconds % 60
                binding.tvTimerStatus.text = getString(R.string.lbl_stopping_in, minutes, secs)
            } else {
                binding.tvTimerStatus.visibility = View.GONE
            }
        }

        setupLanguageChips()
    }

    private fun setupLanguageChips() {
        binding.chipEn.setOnClickListener { viewModel.setLanguage(Locale.US) }
        binding.chipHi.setOnClickListener { viewModel.setLanguage(Locale("hi", "IN")) }
        binding.chipMr.setOnClickListener { viewModel.setLanguage(Locale("mr", "IN")) }

        viewModel.selectedLanguage.observe(viewLifecycleOwner) { locale ->
            when (locale.language) {
                "en" -> binding.chipEn.isChecked = true
                "hi" -> binding.chipHi.isChecked = true
                "mr" -> binding.chipMr.isChecked = true
            }
        }
    }

    private fun updatePlayPauseButton(speaking: Boolean, paused: Boolean) {
        if (speaking) {
            binding.btnPlayPause.text = getString(R.string.btn_pause)
            binding.btnPlayPause.setIconResource(com.rugvedsarika.voicereader.R.drawable.ic_pause)
        } else if (paused) {
            binding.btnPlayPause.text = getString(R.string.btn_resume)
            binding.btnPlayPause.setIconResource(com.rugvedsarika.voicereader.R.drawable.ic_play_arrow)
        } else {
            binding.btnPlayPause.text = getString(R.string.btn_speak)
            binding.btnPlayPause.setIconResource(com.rugvedsarika.voicereader.R.drawable.ic_play_arrow)
        }
    }

    private fun autoScrollToText(charIndex: Int) {
        val layout = binding.textToSpeak.layout ?: return
        val line = layout.getLineForOffset(charIndex)
        val lineTop = layout.getLineTop(line)
        val lineBottom = layout.getLineBottom(line)
        
        val scrollY = binding.textToSpeak.scrollY
        val height = binding.textToSpeak.height
        
        if (lineTop < scrollY || lineBottom > scrollY + height) {
            binding.textToSpeak.scrollTo(0, lineTop)
        }
    }

    private fun showSleepTimerDialog() {
        val options = arrayOf(
            getString(R.string.opt_5_mins),
            getString(R.string.opt_15_mins),
            getString(R.string.opt_30_mins),
            getString(R.string.opt_60_mins),
            getString(R.string.opt_cancel_timer)
        )
        val minutes = intArrayOf(5, 15, 30, 60, 0)
        
        com.google.android.material.dialog.MaterialAlertDialogBuilder(requireContext())
            .setTitle(getString(R.string.title_sleep_timer))
            .setItems(options) { _, which ->
                if (minutes[which] == 0) {
                    viewModel.cancelSleepTimer()
                } else {
                    viewModel.startSleepTimer(minutes[which])
                }
            }
            .show()
    }

    private fun handleFileImport(uri: android.net.Uri) {
        try {
            val contentResolver = requireContext().contentResolver
            contentResolver.openInputStream(uri)?.use { inputStream ->
                val text = inputStream.bufferedReader().use { it.readText() }
                binding.textToSpeak.setText(text)
                Toast.makeText(context, getString(R.string.msg_file_imported), Toast.LENGTH_SHORT).show()
            }
        } catch (e: Exception) {
            Toast.makeText(context, getString(R.string.msg_error_import, e.message), Toast.LENGTH_SHORT).show()
        }
    }

    private fun showWebImportDialog() {
        val input = com.google.android.material.textfield.TextInputEditText(requireContext())
        input.hint = "https://example.com"
        
        com.google.android.material.dialog.MaterialAlertDialogBuilder(requireContext())
            .setTitle("Import Text from Web")
            .setView(input)
            .setPositiveButton("Import") { _, _ ->
                val url = input.text.toString()
                if (url.isNotEmpty()) {
                    fetchWebText(url)
                }
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    private fun fetchWebText(urlString: String) {
        val url = if (!urlString.startsWith("http")) "https://$urlString" else urlString
        
        Thread {
            try {
                val connection = java.net.URL(url).openConnection() as java.net.HttpURLConnection
                connection.requestMethod = "GET"
                val text = connection.inputStream.bufferedReader().use { it.readText() }
                
                val cleanText = text.replace(Regex("<script.*?>.*?</script>", RegexOption.DOT_MATCHES_ALL), "")
                    .replace(Regex("<style.*?>.*?</style>", RegexOption.DOT_MATCHES_ALL), "")
                    .replace(Regex("<.*?>"), "")
                    .replace(Regex("&nbsp;"), " ")
                    .replace(Regex("\\s+"), " ")
                    .trim()

                activity?.runOnUiThread {
                    binding.textToSpeak.setText(cleanText)
                    Toast.makeText(context, getString(R.string.msg_web_imported), Toast.LENGTH_SHORT).show()
                }
            } catch (e: Exception) {
                activity?.runOnUiThread {
                    Toast.makeText(context, getString(R.string.msg_error_web, e.message), Toast.LENGTH_SHORT).show()
                }
            }
        }.start()
    }

    private fun checkCameraPermissionAndStartOCR() {
        when {
            ContextCompat.checkSelfPermission(requireContext(), android.Manifest.permission.CAMERA) == android.content.pm.PackageManager.PERMISSION_GRANTED -> {
                startOCR()
            }
            else -> {
                cameraPermissionLauncher.launch(android.Manifest.permission.CAMERA)
            }
        }
    }

    private fun startOCR() {
        val intent = Intent(requireContext(), OCRScannerActivity::class.java)
        ocrLauncher.launch(intent)
    }

    private fun highlightText(start: Int, end: Int) {
        val fullText = binding.textToSpeak.text.toString()
        if (fullText.isEmpty()) return

        val spannable = SpannableString(fullText)
        if (start < end && end <= fullText.length) {
            val highlightColor = ContextCompat.getColor(requireContext(), com.rugvedsarika.voicereader.R.color.accent)
            spannable.setSpan(
                BackgroundColorSpan(highlightColor),
                start,
                end,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
            )
        }
        
        val cursor = binding.textToSpeak.selectionStart
        binding.textToSpeak.setText(spannable)
        binding.textToSpeak.setSelection(cursor)
    }

    private fun saveAudio() {
        val text = viewModel.textToSpeak.value ?: ""
        if (text.isEmpty()) {
            Toast.makeText(context, "Please enter some text", Toast.LENGTH_SHORT).show()
            return
        }

        val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
        val fileName = "VoiceReader_$timeStamp.wav"
        
        val storageDir = context?.getExternalFilesDir(Environment.DIRECTORY_MUSIC)
        val file = File(storageDir, fileName)

        viewModel.saveToFile(file) { success ->
            activity?.runOnUiThread {
                if (success) {
                    Toast.makeText(context, "Saved: $fileName", Toast.LENGTH_LONG).show()
                } else {
                    Toast.makeText(context, "Failed to save audio", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}
