/**
 * ProjectLaogai
 *
 * Copyright 2019-2020  <seil0@mosad.xyz>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 *
 */

package org.mosad.seil0.projectlaogai.fragments

import android.os.Bundle
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.afollestad.aesthetic.Aesthetic
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.WhichButton
import com.afollestad.materialdialogs.actions.getActionButton
import com.afollestad.materialdialogs.color.colorChooser
import com.afollestad.materialdialogs.list.listItemsMultiChoice
import com.afollestad.materialdialogs.list.listItemsSingleChoice
import de.psdev.licensesdialog.LicensesDialog
import kotlinx.coroutines.*
import org.mosad.seil0.projectlaogai.BuildConfig
import org.mosad.seil0.projectlaogai.R
import org.mosad.seil0.projectlaogai.controller.GradesController
import org.mosad.seil0.projectlaogai.controller.cache.CacheController
import org.mosad.seil0.projectlaogai.controller.cache.CacheController.Companion.coursesList
import org.mosad.seil0.projectlaogai.controller.cache.TimetableController
import org.mosad.seil0.projectlaogai.controller.preferences.EncryptedPreferences
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences
import org.mosad.seil0.projectlaogai.databinding.FragmentSettingsBinding
import org.mosad.seil0.projectlaogai.uicomponents.dialogs.CourseSelectionDialog
import org.mosad.seil0.projectlaogai.uicomponents.dialogs.LoadingDialog
import org.mosad.seil0.projectlaogai.uicomponents.dialogs.LoginDialog
import org.mosad.seil0.projectlaogai.util.DataTypes
import java.util.*

/**
 * The settings controller class
 * contains all needed parts to display and the settings screen
 */
class SettingsFragment : Fragment() {

    private lateinit var binding: FragmentSettingsBinding

    private var selectedTheme = DataTypes.Theme.Light

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

    /**
     * initialize the settings gui
     */
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        initActions()

        binding.textUser.text = EncryptedPreferences.email.ifEmpty { resources.getString(R.string.sample_user) }
        binding.textCourse.text = Preferences.course.courseName
        binding.textAboutDesc.text =  resources.getString(R.string.about_version, BuildConfig.VERSION_NAME, getString(R.string.build_time))
        binding.textGradesSyncDesc.text = if (Preferences.gradesSyncInterval == 0) {
            resources.getString(R.string.grades_sync_desc_never)
        } else {
            resources.getString(R.string.grades_sync_desc, Preferences.gradesSyncInterval)
        }
        binding.switchBuffet.isChecked = Preferences.showBuffet // init switch

        val outValue = TypedValue()
        activity!!.theme.resolveAttribute(R.attr.themeName, outValue, true)
        when(outValue.string) {
            "light" -> {
                binding.switchBuffet.setTextColor(activity!!.resources.getColor(R.color.textPrimaryLight, activity!!.theme))
                selectedTheme = DataTypes.Theme.Light
                selectedTheme.string = resources.getString(R.string.themeLight)
            }
            "dark" -> {
                binding.switchBuffet.setTextColor(activity!!.resources.getColor(R.color.textPrimaryDark, activity!!.theme))
                selectedTheme = DataTypes.Theme.Dark
                selectedTheme.string = resources.getString(R.string.themeDark)
            }
            "black" -> {
                binding.switchBuffet.setTextColor(activity!!.resources.getColor(R.color.textPrimaryDark, activity!!.theme))
                selectedTheme = DataTypes.Theme.Black
                selectedTheme.string = resources.getString(R.string.themeBlack)
            }
        }
        binding.textThemeSelected.text = selectedTheme.string
    }

    /**
     * initialize some actions for SettingsFragment elements
     */
    private fun initActions() {
        binding.linLayoutUser.setOnClickListener {
            // open a new dialog
            LoginDialog(context!!)
                .positiveButton {
                    EncryptedPreferences.saveCredentials(email, password, context)
                }
                .show {
                    email = EncryptedPreferences.email
                    password = ""
                }
        }

        binding.linLayoutUser.setOnLongClickListener {
            Preferences.oGiants = true // enable easter egg
            return@setOnLongClickListener true
        }

        binding.linLayoutCourse.setOnClickListener {
            CourseSelectionDialog(context!!).show {
                list = coursesList.map { it.courseName }
                listItems {
                    val loadingDialog = LoadingDialog(context)
                    loadingDialog.show()

                    GlobalScope.launch(Dispatchers.Default) {
                        Preferences.saveCourse(context, coursesList[selectedIndex]) // save the course

                        // update current & next weeks timetable
                        val threads = listOf(
                            CacheController.updateTimetable(Preferences.course.courseName, 0, context),
                            CacheController.updateTimetable(Preferences.course.courseName, 1, context)
                        )
                        threads.joinAll() // blocking since we want the new data

                        withContext(Dispatchers.Main) {
                            loadingDialog.dismiss()
                        }
                    }
                }
                onDismiss {
                    binding.textCourse.text = Preferences.course.courseName // update txtView after the dialog is dismissed
                }
            }
        }

        binding.linLayoutManageLessons.setOnClickListener {
            val lessons = ArrayList<String>()
            TimetableController.subjectMap.forEach { pair ->
                pair.value.forEach {
                    lessons.add("${pair.key} - $it")
                }
            }

            MaterialDialog(context!!).show {
                title(R.string.manage_lessons)
                positiveButton(R.string.delete)
                negativeButton(R.string.cancel)
                getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.colorAccent)
                getActionButton(WhichButton.NEGATIVE).updateTextColor(Preferences.colorAccent)

                listItemsMultiChoice(items = lessons) { _, _, items ->
                    items.forEach {
                        val list = it.split(" - ")
                        TimetableController.removeSubject(list[0], list[1], context)
                    }
                }
            }
        }

        binding.linLayoutAbout.setOnClickListener {
            // open a new info dialog
            MaterialDialog(context!!)
                .title(R.string.about_dialog_heading)
                .message(R.string.about_dialog_text)
                .show()
        }

        binding.linLayoutLicence.setOnClickListener {
            // do the theme magic, as the lib's theme support is broken
            val outValue = TypedValue()
            context!!.theme.resolveAttribute(R.attr.themeName, outValue, true)

            val dialogCss = when (outValue.string) {
                "light" -> R.string.license_dialog_style_light
                else -> R.string.license_dialog_style_dark
            }

            val themeId = when (outValue.string) {
                "light" -> R.style.AppTheme_Light
                else -> R.style.LicensesDialogTheme_Dark
            }

            // open a new license dialog
            LicensesDialog.Builder(context!!)
                .setNotices(R.raw.notices)
                .setTitle(R.string.licenses)
                .setIncludeOwnLicense(true)
                .setThemeResourceId(themeId)
                .setNoticesCssStyle(dialogCss)
                .build()
                .show()
        }

        binding.linLayoutTheme.setOnClickListener {
            val themes = listOf(
                resources.getString(R.string.themeLight),
                resources.getString(R.string.themeDark),
                resources.getString(R.string.themeBlack)
            )

            MaterialDialog(context!!).show {
                title(R.string.theme)
                listItemsSingleChoice(items = themes, initialSelection = selectedTheme.ordinal) { _, index, _ ->
                    Aesthetic.config {
                        when (index) {
                            0 -> activityTheme(R.style.AppTheme_Light)
                            1 -> activityTheme(R.style.AppTheme_Dark)
                            2 -> activityTheme(R.style.AppTheme_Black)
                            else -> activityTheme(R.style.AppTheme_Light)
                        }
                        apply()
                    }
                }
            }
        }

        binding.linLayoutPrimaryColor.setOnClickListener {
            // open a new color chooser dialog
            MaterialDialog(context!!)
                .colorChooser(DataTypes().primaryColors, allowCustomArgb = true, initialSelection = Preferences.colorPrimary) { _, color ->
                    binding.viewPrimaryColor.setBackgroundColor(color)
                    Aesthetic.config {
                        colorPrimary(color)
                        colorPrimaryDark(color)
                        apply()
                    }
                    Preferences.saveColorPrimary(context!!, color)
                }
                .show {
                    title(R.string.primary_color)
                    positiveButton(R.string.select)
                    getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.colorAccent)
                }

        }

        binding.linLayoutAccentColor.setOnClickListener {
            // open a new color chooser dialog
            MaterialDialog(context!!)
                .colorChooser(DataTypes().accentColors, allowCustomArgb = true, initialSelection = Preferences.colorAccent) { _, color ->
                    binding.viewAccentColor.setBackgroundColor(color)
                    Aesthetic.config {
                        colorAccent(color)
                        apply()
                    }

                    Preferences.saveColorAccent(context!!, color)
                }
                .show{
                    title(R.string.accent_color)
                    positiveButton(R.string.select)
                    getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.colorAccent)
                }
        }

        binding.linLayoutGradesSync.setOnClickListener {
            val items = resources.getStringArray(R.array.syncInterval).toList()
            val initial = when (Preferences.gradesSyncInterval) {
                1 -> 1
                3 -> 2
                6 -> 3
                12 -> 4
                else -> 0
            }

            MaterialDialog(context!!)
                .title(R.string.grades_sync)
                .listItemsSingleChoice(items = items, initialSelection = initial) { _, index, _ ->
                val interval = when (index) {
                    1 -> 1
                    2 -> 3
                    3 -> 6
                    4 -> 12
                    else -> 0
                }

                Preferences.saveGradesSync(context!!, interval)
                GradesController.updateBackgroundSync(context!!)

                    binding.textGradesSyncDesc.text = if (Preferences.gradesSyncInterval == 0) {
                    resources.getString(R.string.grades_sync_desc_never)
                } else {
                    resources.getString(R.string.grades_sync_desc, Preferences.gradesSyncInterval)
                }
            }.show()
        }

        binding.switchBuffet.setOnClickListener {
            Preferences.saveShowBuffet(context!!, binding.switchBuffet.isChecked)
        }

    }

}
