package com.dreamteam.timelapse
import android.content.Intent
import android.graphics.Color
import android.graphics.Rect
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.dreamteam.timelapse.data.ApiService
import com.dreamteam.timelapse.data.CaptureQuery
import com.dreamteam.timelapse.data.Confirmation
import com.dreamteam.timelapse.data.Measurement
import com.dreamteam.timelapse.data.Project
import com.dreamteam.timelapse.data.ProjectRepository
import com.dreamteam.timelapse.data.VideoRepository
import com.dreamteam.timelapse.databinding.ProjectBinding
import com.github.mikephil.charting.components.Legend
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
import com.github.mikephil.charting.formatter.ValueFormatter
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale


class ProjectActivity : AppCompatActivity() {

    private lateinit var stopingProcedureDialog: AlertDialog
    private lateinit var videoRenderDialog: AlertDialog
    private lateinit var startingProcedureDialog: AlertDialog
    private lateinit var binding: ProjectBinding
    private lateinit var projectRepository: ProjectRepository
    private lateinit var videoRepository: VideoRepository
    private lateinit var apiService: ApiService // Déclare l'apiService
    private var measures: List<Measurement> = emptyList() // Déclare une liste de projets vide
    private var project: Project? = null
    private var imageUrls = emptyList<String>()
    enum class ButtonState {
        START, LOADING, FINISHED, ENDING
    }

    private var buttonState = ButtonState.START

    class GridSpacingItemDecoration(private val spacing: Int) : RecyclerView.ItemDecoration() {
        override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
            val position = parent.getChildAdapterPosition(view) // Position de l'item
            if (position == RecyclerView.NO_POSITION) return

            outRect.left = spacing / 2
            outRect.right = spacing / 2
            outRect.top = spacing
        }
    }

    fun refreshMultiuseButton(){
        val floatingButton = findViewById<FloatingActionButton>(R.id.multiusefloating)
        var icon = when (buttonState) {
            ButtonState.START -> android.R.drawable.ic_media_play
            ButtonState.LOADING -> R.drawable.baseline_stop_24
            ButtonState.FINISHED, ButtonState.ENDING -> android.R.drawable.ic_menu_save
        }
        floatingButton.setImageResource(icon)
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        val retrofit = Retrofit.Builder()
            .baseUrl("https://timelapse.kerboul.me/api/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        apiService = retrofit.create(ApiService::class.java) // Crée une instance d'ApiService
        projectRepository = ProjectRepository(apiService)
        videoRepository = VideoRepository(apiService)

        this.project = intent.getParcelableExtra<Project>("PROJECT")  // -1 est la valeur par défaut si l'ID n'est pas trouvé
        Log.d("project", "La project activity "+this.project?.id+" est créée")

        super.onCreate(savedInstanceState)
        this.binding = ProjectBinding.inflate(layoutInflater)
        setContentView(binding.root)

        initProjectInfo()
        binding.imagesList.layoutManager = GridLayoutManager(this.baseContext, 2, GridLayoutManager.HORIZONTAL, false)
        binding.imagesList.addItemDecoration(GridSpacingItemDecoration(16)) // 16px spacing
        binding.videosList.layoutManager = GridLayoutManager(this.baseContext, 2, GridLayoutManager.HORIZONTAL, false)
        binding.videosList.addItemDecoration(GridSpacingItemDecoration(16)) // 16px spacing
        fetchMeasuresAndRebuildGraph()
        fetchVideos()
        val swipeRefreshLayout = binding.swipeRefreshLayout
        swipeRefreshLayout.setOnRefreshListener {
            fetchMeasuresAndRebuildGraph()
            fetchVideos()
            Log.d("ProjetsFrag", "Actualisation des projets")
        }

        val floatingButton = findViewById<FloatingActionButton>(R.id.multiusefloating)
        this.buttonState = when(project?.getStatusText()) {
            "Brouillon" -> ButtonState.START
            "En Cours" -> ButtonState.LOADING
            "Terminé" -> ButtonState.FINISHED
            "En cours d'arret" -> ButtonState.ENDING
            else -> ButtonState.START
        }
        var icon = when (buttonState) {
            ButtonState.START -> android.R.drawable.ic_media_play
            ButtonState.LOADING -> R.drawable.baseline_stop_24
            ButtonState.FINISHED -> android.R.drawable.ic_menu_save
            ButtonState.ENDING -> android.R.drawable.ic_menu_save
        }
        floatingButton.setImageResource(icon)

        floatingButton.setOnClickListener {
//            when (buttonState) {
//                ButtonState.LOADING -> {
//                    buttonState = ButtonState.FINISHED
//                }
//                else -> {}
//            }
//            refreshMultiuseButton()
            when (buttonState) {
                ButtonState.START -> clickStartProcess()
                ButtonState.LOADING -> clickStopProcess()
                ButtonState.FINISHED, ButtonState.ENDING -> clickSave()
            }
        }


        var but = findViewById<View>(R.id.multiusefloating)
        but.post {
            project?.let {
                createVideoRenderDialog(but, it.id, measures)
                createStopProcedureDialog(but, it.id)
                createStartingProcedureDialog(but, it.id)
            }
        }




        // Bouton flottant
//        binding.fab.setOnClickListener { view ->
//
//        }
    }

    fun fetchVideos(){
        this.project?.let{
            videoRepository.fetchRenderedVideosOfProject(it.id, onSuccess = { videos ->
                val adapter = VideoAdapter(false, videos.toMutableList(), null) //ImageAdapter(imageUrls)
                binding.videosList.adapter = adapter
                binding.swipeRefreshLayout.isRefreshing = false
            }, onError = {errorMessage ->
                Log.e("ProjectActivity", "Fetch Video " + errorMessage)
                fetchVideos()
            })
        }
    }
    fun fetchMeasuresAndRebuildGraph(){
        this.project?.let{
            projectRepository.fetchMeasurementsOfProject(it.id,
                onSuccess = { measures ->
                    Log.d("ProjectActivity", "Mesures reçus : $measures")
                    this.measures = measures
                    if(this.measures.size > 0)
                        initGraph(this.measures)

                    val adapter = ImageAdapter(this.measures.map { m-> "https://timelapse.kerboul.me/api/images/${m.project_id}/${m.order_id}"}) //ImageAdapter(imageUrls)
                    Log.d("ProjectActivity", "Je vais mettre l'adapter")
                    binding.imagesList.adapter = adapter

                    binding.swipeRefreshLayout.isRefreshing = false
                    //this.projectAdapter = ProjectAdapter(this.projects, this) //TODO : Potentiel problème pour les refresh ici (update de l'adapter ou un truc du genre à voir)
                    //this.recyclerView.adapter = this.projectAdapter
                    // Mettre à jour le RecyclerView ou autre traitement
                },
                onError = { errorMessage ->
                    Log.e("ProjectActivity", errorMessage)
                    fetchMeasuresAndRebuildGraph()
                })
        }
    }
    fun initGraph(lm: List<Measurement>) {
        val temperatureHumidityChart = this.binding.temperatureHumidityChart

        // Sort measurements by order_id and map to pairs of value and timestamp
        val temperatures = lm.sortedBy { it.order_id }
            .map { m -> Pair(m.temperature, m.order_id) }
        val humidities = lm.sortedBy { it.order_id }
            .map { m -> Pair(m.humidity, m.order_id) }

        // Create entries for temperature and humidity using timestamps
        val temperatureEntries = temperatures.mapIndexed { index, pair ->
            Entry(index.toFloat(), pair.first)  // Use index for order, but display timestamp
        }

        val humidityEntries = humidities.mapIndexed { index, pair ->
            Entry(index.toFloat(), pair.first)  // Use index for order, but display timestamp
        }

        // Create LineDataSet for each data series
        val temperatureDataSet = LineDataSet(temperatureEntries, "Température").apply {
            color = Color.RED  // Keep color red
            valueTextColor = Color.BLACK
            valueTextSize = 12f
        }

        val humidityDataSet = LineDataSet(humidityEntries, "Hygrométrie").apply {
            color = Color.BLUE  // Keep color blue
            valueTextColor = Color.BLACK
            valueTextSize = 12f
        }

        // Set up the x-axis to display timestamps
        val xAxis = temperatureHumidityChart.xAxis
        xAxis.valueFormatter = object : ValueFormatter() {
            override fun getFormattedValue(value: Float): String {
                val index = value.toInt()
                val sortedList = lm.sortedBy { it.order_id }

                if (index < 0 || index >= sortedList.size) {
                    // Index out of bounds, return empty string or something neutral
                    return ""
                }

                val timestamp = sortedList[index].timestamp
                val date = Date(timestamp.time)
                val sdf = SimpleDateFormat("dd/MM/yyyy:HH:mm:ss", Locale.getDefault())
                return sdf.format(date)
            }
        }

        // Set the minimum and maximum x-axis values based on indices
        val minX = 0f
        val maxX = (lm.size - 1).toFloat()
        xAxis.axisMinimum = minX
        xAxis.axisMaximum = maxX
        xAxis.granularity = 1f  // Ensure each index is plotted
        xAxis.labelRotationAngle = -90f
        xAxis.position = XAxis.XAxisPosition.BOTTOM

        // Configure the left y-axis
        val leftYAxis = temperatureHumidityChart.axisLeft
        leftYAxis.labelCount = 6  // Set the number of labels
        leftYAxis.setLabelCount(6, true)
        leftYAxis.setDrawLabels(true)
        leftYAxis.setDrawAxisLine(true)
        leftYAxis.setDrawGridLines(true)
        leftYAxis.valueFormatter = object : ValueFormatter() {
            override fun getFormattedValue(value: Float): String {
                return "${value.toInt()} C°"  // Append "C°" to the temperature values
            }
        }

        // Configure the right y-axis
        val rightYAxis = temperatureHumidityChart.axisRight
        rightYAxis.labelCount = 6  // Set the number of labels
        rightYAxis.axisMinimum = 0f  // Set minimum value if needed
        rightYAxis.axisMaximum = 100f  // Set maximum value to 100%
        rightYAxis.setLabelCount(6, true)
        rightYAxis.setDrawLabels(true)
        rightYAxis.setDrawAxisLine(true)
        rightYAxis.setDrawGridLines(false)
        rightYAxis.valueFormatter = object : ValueFormatter() {
            override fun getFormattedValue(value: Float): String {
                return "${value.toInt()} %"  // Append "%" to the humidity values
            }
        }

        // Add datasets to the chart
        val dataSets: MutableList<ILineDataSet> = ArrayList()
        dataSets.add(temperatureDataSet)
        dataSets.add(humidityDataSet)

        temperatureHumidityChart.data = LineData(dataSets)
        val description = temperatureHumidityChart.description
        description.text = " "

        // Customize the legend
        val legend: Legend = temperatureHumidityChart.legend
        legend.textColor = Color.BLACK
        legend.textSize = 12f

        // Refresh the chart
        temperatureHumidityChart.invalidate()
    }
    fun initProjectInfo(){
        val nameview = findViewById<TextView>(R.id.project_name)
        val descriptionview = findViewById<TextView>(R.id.project_description)
        val beginview = findViewById<TextView>(R.id.project_start_date)
        val statusview = findViewById<TextView>(R.id.project_status)

        nameview.text = project!!.name
        descriptionview.text = project!!.description
        beginview.text = project!!.start_date.toString()
        statusview.text = project!!.getStatusText()
    }
    private fun clickStartProcess() {
        Log.i("ProjectActivity", "Start collect...")

        // Simule une durée avant la finalisation du processus
//        Handler(Looper.getMainLooper()).postDelayed({
//            val floatingButton = findViewById<FloatingActionButton>(R.id.multiusefloating)
//            floatingButton.setImageResource(android.R.drawable.ic_menu_save) // Icône d'enregistrement
//            buttonState = ButtonState.FINISHED
//        }, 5000) // 5 secondes de chargement
        startingProcedureDialog.show()
    }

    private fun clickStopProcess() {
        Log.i("ProjectActivity", "Stop collect...")
        stopingProcedureDialog.show()
        // Implémente l'arrêt du processus (annulation si nécessaire)
    }

    private fun clickSave() {
        Log.i("ProjectActivity", "Create video...")
        videoRenderDialog.show()
        //videoRepository.createVideo(project.id, measures, )
//        Toast.makeText(context, "Downloading...", Toast.LENGTH_SHORT).show()
//
//        Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
//                .setAction("Action", null) //sert à rien
//                .setAnchorView(R.id.fab).show() //au dessus du bouton mail
        // Implémente la création d'une vidéo
    }

    fun createVideoRenderDialog(viewfortoast: View, projectId: Int, measurements: List<Measurement>) {
        val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val layout: View = inflater.inflate(R.layout.video_render_dialog_layout, findViewById(R.id.layout_root))

        val videoName = layout.findViewById<EditText>(R.id.video_name_dialog)
        //val videoResolution = layout.findViewById<EditText>(R.id.video_resolution_dialog)
        val videoDuration = layout.findViewById<EditText>(R.id.video_duration_dialog)

        val builder = AlertDialog.Builder(this)
        builder.setView(layout)
            .setPositiveButton("Render Video") { dialog, _ ->
                val name = videoName.text.toString()
                //val resolution = videoResolution.text.toString()
                val durationText = videoDuration.text.toString()

                if (name.isBlank() || durationText.isBlank()) {
                    Snackbar.make(viewfortoast, "All fields must be filled", Snackbar.LENGTH_LONG)
                        .show()
                    return@setPositiveButton
                }

                val duration = durationText.toIntOrNull()
                if (duration == null || duration <= 0) {
                    Snackbar.make(viewfortoast, "Invalid duration", Snackbar.LENGTH_LONG)
                        .show()
                    return@setPositiveButton
                }

                val onSuccess: (Confirmation?) -> Unit = {
                    dialog.dismiss()
                    Snackbar.make(viewfortoast, "Video render started", Snackbar.LENGTH_LONG)
                        .show()
                }

                val onError: (String) -> Unit = { error ->
                    Snackbar.make(viewfortoast, "Error: $error", Snackbar.LENGTH_LONG)
                        .show()
                }

                videoRepository.createVideo(projectId, measures, name, "1920x1080", duration, onSuccess, onError)
            }
            .setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() }

        this.videoRenderDialog = builder.create()
    }
    fun createStartingProcedureDialog(viewfortoast: View, projectId: Int) {
        val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val layout: View = inflater.inflate(R.layout.capture_start_dialog_layout, findViewById(R.id.layout_root))

        val intervalView = layout.findViewById<EditText>(R.id.interval)
        //val videoResolution = layout.findViewById<EditText>(R.id.video_resolution_dialog)
        val nbImView = layout.findViewById<EditText>(R.id.nb_images)

        val builder = AlertDialog.Builder(this)
        builder.setView(layout)
            .setPositiveButton("Run capture procedure") { dialog, _ ->
                val intervalStr = intervalView.text.toString()
                //val resolution = videoResolution.text.toString()
                val nb_imagesStr = nbImView.text.toString()

                if (intervalStr.isBlank() || nb_imagesStr.isBlank()) {
                    Snackbar.make(viewfortoast, "Les champs doivent être remplis", Snackbar.LENGTH_LONG)
                        .show()
                    return@setPositiveButton
                }

                val interval = intervalStr.toIntOrNull()
                val nb_images = nb_imagesStr.toIntOrNull()
                if (interval == null || interval <= 0 || nb_images == null || nb_images <= 0) {
                    Snackbar.make(viewfortoast, "Les chiffres fournis doivent être superieurs à 1", Snackbar.LENGTH_LONG)
                        .show()
                    return@setPositiveButton
                }

                val onSuccess: () -> Unit = {
                    dialog.dismiss()
                    Snackbar.make(viewfortoast, "Processus de capture lancé", Snackbar.LENGTH_LONG)
                        .show()
                    buttonState = ButtonState.LOADING
                    refreshMultiuseButton()

                }

                val onError: (String) -> Unit = { error ->
                    Snackbar.make(viewfortoast, "Error : $error", Snackbar.LENGTH_LONG)
                        .show()
                }

                apiService.procedureStart(CaptureQuery(interval, nb_images, projectId)).enqueue(object :
                    Callback<Void> {
                    override fun onResponse(call: Call<Void>, response: Response<Void>) {
                        if (response.isSuccessful) {
                            refreshProjectInfo(onSuccess, onError)
                        } else {
                            onError("Erreur serveur : ${response.code()}")
                        }
                    }

                    override fun onFailure(call: Call<Void>, t: Throwable) {
                        onError("Erreur réseau : ${t.message}")
                    }
                })
            }
            .setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() }

        this.startingProcedureDialog = builder.create()
    }
    fun createStopProcedureDialog(viewfortoast: View, projectId: Int) {
        val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val layout: View = inflater.inflate(R.layout.capture_stop_dialog_layout, findViewById(R.id.layout_root))

        val builder = AlertDialog.Builder(this)
        builder.setView(layout)
            .setPositiveButton("Stop") { dialog, _ ->
                val onSuccess: () -> Unit = {
                    dialog.dismiss()
                    Snackbar.make(viewfortoast, "Processus arreté", Snackbar.LENGTH_LONG)
                        .show()
                    buttonState = ButtonState.FINISHED
                    refreshMultiuseButton()

                }

                val onError: (String) -> Unit = { error ->
                    Snackbar.make(viewfortoast, "Error : $error", Snackbar.LENGTH_LONG)
                        .show()
                }

                apiService.procedureStop().enqueue(object :
                    Callback<Void> {
                    override fun onResponse(call: Call<Void>, response: Response<Void>) {
                        if (response.isSuccessful) {
                            refreshProjectInfo(onSuccess, onError)
                        } else {
                            onError("Erreur serveur : ${response.code()}")
                        }
                    }

                    override fun onFailure(call: Call<Void>, t: Throwable) {
                        onError("Erreur réseau : ${t.message}")
                    }
                })
            }
            .setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() }

        this.stopingProcedureDialog = builder.create()
    }

    fun refreshProjectInfo(cbGood: ()->Unit, cbBad: (String)->Unit){
        this.project?.let {
            projectRepository.fetchProject(it.id, onSuccess = {
                Log.i("ProjectActivity", "Pull projet ok")
                this.project = it;
                this.initProjectInfo()
                cbGood()
            }, onError = {
                Log.i("ProjectActivity", "Erreur de pull projet : $it")
                cbBad("Erreur de pull projet : $it")
            })
        }
    }

    override fun onBackPressed() {
        super.onBackPressed()
        startActivity(Intent(this, MainActivity::class.java))
    }
}
