/**
 * 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.content.Context
import android.os.Bundle
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.Switch
import android.widget.TextView
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.callbacks.onDismiss
import com.afollestad.materialdialogs.color.colorChooser
import com.afollestad.materialdialogs.customview.customView
import com.afollestad.materialdialogs.list.listItems
import com.afollestad.materialdialogs.list.listItemsMultiChoice
import com.afollestad.materialdialogs.list.listItemsSingleChoice
import de.psdev.licensesdialog.LicensesDialog
import kotlinx.android.synthetic.main.fragment_settings.*
import kotlinx.coroutines.*
import org.mosad.seil0.projectlaogai.BuildConfig
import org.mosad.seil0.projectlaogai.R
import org.mosad.seil0.projectlaogai.controller.CacheController
import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.coursesList
import org.mosad.seil0.projectlaogai.controller.PreferencesController
import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cColorAccent
import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cColorPrimary
import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cCourse
import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cShowBuffet
import org.mosad.seil0.projectlaogai.controller.TimetableController
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 linLayoutUser: LinearLayout
    private lateinit var linLayoutCourse: LinearLayout
    private lateinit var linLayoutManageLessons: LinearLayout
    private lateinit var linLayoutAbout: LinearLayout
    private lateinit var linLayoutLicence: LinearLayout
    private lateinit var linLayoutTheme: LinearLayout
    private lateinit var linLayoutPrimaryColor: LinearLayout
    private lateinit var linLayoutAccentColor: LinearLayout
    private lateinit var switchBuffet: Switch
    private lateinit var txtViewCourse: TextView

    private var selectedTheme = DataTypes.Theme.Light

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

        val view: View = inflater.inflate(R.layout.fragment_settings, container, false)

        linLayoutUser = view.findViewById(R.id.linLayout_User)
        linLayoutCourse = view.findViewById(R.id.linLayout_Course)
        linLayoutManageLessons = view.findViewById(R.id.linLayout_ManageLessons)
        linLayoutAbout = view.findViewById(R.id.linLayout_About)
        linLayoutLicence = view.findViewById(R.id.linLayout_Licence)
        linLayoutTheme = view.findViewById(R.id.linLayout_Theme)
        linLayoutPrimaryColor = view.findViewById(R.id.linLayout_PrimaryColor)
        linLayoutAccentColor = view.findViewById(R.id.linLayout_AccentColor)
        switchBuffet = view.findViewById(R.id.switch_buffet)
        // if we call txtView_Course via KAE view binding it'll result in a NPE in the onDismissed call
        txtViewCourse = view.findViewById(R.id.txtView_Course)

        initActions()

        // Inflate the layout for this fragment
        return view
    }

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

        // initialize the settings gui
        txtView_Course.text = cCourse.courseName
        txtView_AboutDesc.text =  resources.getString(R.string.about_version, BuildConfig.VERSION_NAME, getString(R.string.build_time))
        switch_buffet.isChecked = cShowBuffet // init switch

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

    /**
     * initialize some actions for SettingsFragment elements
     */
    private fun initActions() {
        linLayoutUser.setOnClickListener {
            // open a new dialog
        }

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

        linLayoutCourse.setOnClickListener {
            selectCourse(context!!).show {
                onDismiss {
                    txtViewCourse.text = cCourse.courseName // update txtView after the dialog is dismissed
                }
            }
        }

        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(cColorAccent)
                getActionButton(WhichButton.NEGATIVE).updateTextColor(cColorAccent)

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

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

        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()
        }

        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()
                    }
                }
            }
        }

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

        }

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

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

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

    }

    fun selectCourse(context: Context) : MaterialDialog {
        val courseNameList = ArrayList<String>()
        coursesList.forEach { (_, courseName) ->
            courseNameList.add(courseName)
        }

        // return a new course selection dialog
        return MaterialDialog(context)
            .title(R.string.select_course)
            .listItems(items = courseNameList) { _, index, _ ->

                val loadingDialog = MaterialDialog(context).cancelable(false)
                    .cancelOnTouchOutside(false)
                    .customView(R.layout.dialog_loading)
                loadingDialog.show()

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

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

                    withContext(Dispatchers.Main) {
                        loadingDialog.dismiss()
                    }
                }

            }
    }

}
