/*
 * Copyright (c) 2020 Hemanth Savarla.
 *
 * Licensed under the GNU General Public License v3
 *
 * This 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 software 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.
 *
 */
@file:JvmName("ColorExtensionsUtils")

package allen.town.focus_common.extensions

import allen.town.focus_common.R
import allen.town.focus_common.util.BasePreferenceUtil.materialYou
import android.app.Dialog
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.widget.Button
import android.widget.CheckBox
import android.widget.SeekBar
import android.widget.TextView
import androidx.annotation.AttrRes
import androidx.annotation.CheckResult
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.appcompat.widget.AppCompatImageButton
import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import androidx.core.graphics.drawable.DrawableCompat
import androidx.fragment.app.Fragment
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.*
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.google.android.material.chip.Chip
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.material.slider.Slider
import com.google.android.material.textfield.TextInputLayout

fun Int.ripAlpha(): Int {
    return ColorUtil.stripAlpha(this)
}

fun Dialog.colorControlNormal() = resolveColor(android.R.attr.colorControlNormal)

fun Toolbar.backgroundTintList() {
    val surfaceColor = ATHUtil.resolveColor(context, com.google.android.material.R.attr.colorSurface, Color.BLACK)
    val colorStateList = ColorStateList.valueOf(surfaceColor)
    backgroundTintList = colorStateList
}

fun Context.accentColor() = ThemeStore.accentColor(this)

fun Fragment.accentColor() = ThemeStore.accentColor(requireContext())

fun Context.surfaceColor() = resolveColor(com.google.android.material.R.attr.colorSurface, Color.WHITE)

fun Fragment.surfaceColor() = resolveColor(com.google.android.material.R.attr.colorSurface, Color.WHITE)

fun Context.surfaceColor(fallBackColor: Int) = resolveColor(com.google.android.material.R.attr.colorSurface, fallBackColor)

fun Fragment.surfaceColor(fallBackColor: Int) = resolveColor(com.google.android.material.R.attr.colorSurface, fallBackColor)

fun Context.textColorSecondary() = resolveColor(android.R.attr.textColorSecondary)

fun Fragment.textColorSecondary() = resolveColor(android.R.attr.textColorSecondary)

fun Context.colorControlNormal() = resolveColor(android.R.attr.colorControlNormal)

fun Fragment.colorControlNormal() = resolveColor(android.R.attr.colorControlNormal)

fun Context.colorBackground() = resolveColor(android.R.attr.colorBackground)

fun Fragment.colorBackground() = resolveColor(android.R.attr.colorBackground)

fun Context.textColorPrimary() = resolveColor(android.R.attr.textColorPrimary)

fun Fragment.textColorPrimary() = resolveColor(android.R.attr.textColorPrimary)

fun Context.defaultFooterColor() = resolveColor(code.name.monkey.appthemehelper.R.attr.defaultFooterColor)

fun Fragment.defaultFooterColor() = resolveColor(code.name.monkey.appthemehelper.R.attr.defaultFooterColor)

fun Context.resolveColor(@AttrRes attr: Int, fallBackColor: Int = 0) =
    ATHUtil.resolveColor(this, attr, fallBackColor)

fun Fragment.resolveColor(@AttrRes attr: Int, fallBackColor: Int = 0) =
    ATHUtil.resolveColor(requireContext(), attr, fallBackColor)

fun Dialog.resolveColor(@AttrRes attr: Int, fallBackColor: Int = 0) =
    ATHUtil.resolveColor(context, attr, fallBackColor)

// Don't apply accent colors if Follow system theme is enabled
// Material Components will take care of applying Follow system theme colors
fun CheckBox.addAccentColor() {
    if (materialYou) return
    buttonTintList = ColorStateList.valueOf(ThemeStore.accentColor(context))
}


fun SeekBar.addAccentColor() {
    if (materialYou) return
    val colorState = ColorStateList.valueOf(ThemeStore.accentColor(context))
    progressTintList = colorState
    thumbTintList = colorState
}

fun Slider.addAccentColor() {
    if (materialYou) return
    val accentColor = ThemeStore.accentColor(context)
    trackActiveTintList = accentColor.colorStateList
    trackInactiveTintList = ColorUtil.withAlpha(accentColor, 0.5F).colorStateList
    thumbTintList = accentColor.colorStateList
}

fun Slider.accent() {
    if (materialYou) return
    val accentColor = context.accentColor()
    thumbTintList = accentColor.colorStateList
    trackActiveTintList = accentColor.colorStateList
    trackInactiveTintList = ColorUtil.withAlpha(accentColor, 0.1F).colorStateList
}

fun Button.accentTextColor(context: Context) {
    if (materialYou) return
    setTextColor(ThemeStore.accentColor(context).addAlpha(0.8F))
}

fun TextView.accentColor() {
    setTextColor(ThemeStore.accentColor(context).addAlpha(0.8F))
}

fun Chip.accentBackgroundColor() {
    if (materialYou) return
    val sl = ColorStateList(
        arrayOf(
            intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_checked),
            intArrayOf(android.R.attr.state_enabled, android.R.attr.state_checked)
        ), intArrayOf(
            context.surfaceColor(),
            ThemeStore.accentColor(context).addAlpha(accentAlpha)
        )
    )

    chipBackgroundColor = sl
}

fun Chip.elevatedAccentColor() {
    if (materialYou) return
    val color = context.darkAccentColorVariant()
//    rippleColor = ColorStateList.valueOf(color)
    setTextColor(MaterialValueHelper.getPrimaryTextColor(context, color.isColorLight))

    chipBackgroundColor = ColorStateList.valueOf(color)
}

fun MaterialButton.accentBackgroundColor(context: Context) {
    if (materialYou) return
    backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(context))
}
fun Int.addAlpha(alpha: Float): Int {
    return ColorUtil.withAlpha(this, alpha)
}

//次级强调色，很多按钮直接用主题色不太合适
const val accentAlpha = 0.12F

fun MaterialButton.accentOutlineColor() {
    if (materialYou) return
    val color = ThemeStore.accentColor(context)
    val colorStateList = ColorStateList.valueOf(color)
    iconTint = colorStateList
    strokeColor = colorStateList
    setTextColor(colorStateList)
    rippleColor = ColorStateList.valueOf(color.addAlpha(accentAlpha))
}

fun MaterialButton.accentOutlineBackgroundColor() {
    if (materialYou) return
    val color = ThemeStore.accentColor(context)
    val colorStateList = ColorStateList.valueOf(color)
//    iconTint = colorStateList
//    strokeColor = colorStateList
//    setTextColor(colorStateList)
    val sl = ColorStateList(
        arrayOf(
            intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_checked),
            intArrayOf(android.R.attr.state_enabled, android.R.attr.state_checked)
        ), intArrayOf(
            context.surfaceColor(),
            ThemeStore.accentColor(context).addAlpha(accentAlpha)
        )
    )

    backgroundTintList = sl
//    rippleColor = colorStateList
}

fun MaterialCardView.accentBackgroundColor() {
    if (materialYou) return
    val color = context.darkAccentColorVariant()
//    rippleColor = ColorStateList.valueOf(color)
    setCardBackgroundColor(color)
}

fun MaterialButton.elevatedAccentColor() {
    if (materialYou) return
    val color = context.darkAccentColorVariant()
//    rippleColor = ColorStateList.valueOf(color)
    setBackgroundColor(color)
    setTextColor(MaterialValueHelper.getPrimaryTextColor(context, color.isColorLight))
    iconTint = ColorStateList.valueOf(context.accentColor())
}

fun SeekBar.applyColor(@ColorInt color: Int) {
    thumbTintList = ColorStateList.valueOf(color)
    progressTintList = ColorStateList.valueOf(color)
    progressBackgroundTintList = ColorStateList.valueOf(color)
}

fun ExtendedFloatingActionButton.accentColor() {
    if (materialYou) return
    val color = ThemeStore.accentColor(context)
    val textColor = MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(color))
    val colorStateList = ColorStateList.valueOf(color)
    val textColorStateList = ColorStateList.valueOf(textColor)
    backgroundTintList = colorStateList
    setTextColor(textColorStateList)
    iconTint = textColorStateList
}

fun FloatingActionButton.accentColor() {
    if (materialYou) return
    val color = ThemeStore.accentColor(context)
    val textColor = MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(color))
    backgroundTintList = ColorStateList.valueOf(color)
    imageTintList = ColorStateList.valueOf(textColor)
}

fun MaterialButton.applyColor(color: Int) {
    val backgroundColorStateList = ColorStateList.valueOf(color)
    val textColorColorStateList = ColorStateList.valueOf(
        MaterialValueHelper.getPrimaryTextColor(
            context,
            ColorUtil.isColorLight(color)
        )
    )
    backgroundTintList = backgroundColorStateList
    setTextColor(textColorColorStateList)
    iconTint = textColorColorStateList
}

fun MaterialButton.accentColor() {
    if (materialYou) return
    applyColor(ThemeStore.accentColor(context))
}

fun MaterialButton.applyOutlineColor(color: Int) {
    val colorStateList = ColorStateList.valueOf(color)
    iconTint = colorStateList
    strokeColor = colorStateList
    setTextColor(colorStateList)
    rippleColor = colorStateList
}

fun TextInputLayout.accentColor() {
    if (materialYou) return
    val accentColor = ThemeStore.accentColor(context)
    val colorState = ColorStateList.valueOf(accentColor)
    boxStrokeColor = accentColor
    defaultHintTextColor = colorState
    isHintAnimationEnabled = true
}

fun CircularProgressIndicator.accentColor() {
//    if (materialYou) return
    val color = ThemeStore.accentColor(context)
    setIndicatorColor(color)
    trackColor = ColorUtil.withAlpha(color, 0.2f)
}

fun CircularProgressIndicator.applyColor(color: Int) {
    setIndicatorColor(color)
    trackColor = ColorUtil.withAlpha(color, 0.2f)
}

fun CircularProgressIndicator.accentColorAndTransparentBackground() {
    if (materialYou) return
    val color = ThemeStore.accentColor(context)
    setIndicatorColor(color)
    trackColor = ContextCompat.getColor(context,android.R.color.transparent)
}

fun LinearProgressIndicator.accentColor() {
    if (materialYou) return
    val color = ThemeStore.accentColor(context)
    setIndicatorColor(color)
    trackColor = ColorUtil.withAlpha(color, 0.2f)
}

fun AppCompatImageView.accentColor(): Int = ThemeStore.accentColor(context)

fun AppCompatImageView.applyAccentColor() {
    val colorState = ColorStateList.valueOf(ThemeStore.accentColor(context))
    imageTintList = colorState
}

fun AppCompatImageButton.applyAccentColor() {
    val colorState = android.content.res.ColorStateList.valueOf(code.name.monkey.appthemehelper.ThemeStore.accentColor(context))
    imageTintList = colorState
}

fun TextInputLayout.setTint(background: Boolean = true) {
    if (materialYou) return
    val accentColor = ThemeStore.accentColor(context)
    val colorState = ColorStateList.valueOf(accentColor)

    if (background) {
        backgroundTintList = colorState
        defaultHintTextColor = colorState
    } else {
        boxStrokeColor = accentColor
        defaultHintTextColor = colorState
        isHintAnimationEnabled = true
    }
}

@CheckResult
fun Drawable.tint(@ColorInt color: Int): Drawable {
    val tintedDrawable = DrawableCompat.wrap(this).mutate()
    DrawableCompat.setTint(this, color)
    return tintedDrawable
}

@CheckResult
fun Drawable.tint(context: Context, @ColorRes color: Int): Drawable =
    tint(context.getColorCompat(color))

@ColorInt
fun Context.getColorCompat(@ColorRes colorRes: Int): Int {
    return ContextCompat.getColor(this, colorRes)
}

@ColorInt
fun Context.darkAccentColor(): Int {
    return ColorUtils.blendARGB(
        accentColor(),
        surfaceColor(),
        if (surfaceColor().isColorLight) 0.9f else 0.92f
    )
}

@ColorInt
fun Context.darkAccentColorVariant(): Int {
    return ColorUtils.blendARGB(
        accentColor(),
        surfaceColor(),
        if (surfaceColor().isColorLight) 0.9f else 0.95f
    )
}

@ColorInt
fun Context.accentColorVariant(): Int {
    return if (surfaceColor().isColorLight) {
        accentColor().darkerColor
    } else {
        accentColor().lighterColor
    }
}

inline val @receiver:ColorInt Int.isColorLight
    get() = ColorUtil.isColorLight(this)

inline val @receiver:ColorInt Int.lighterColor
    get() = ColorUtil.lightenColor(this)

inline val @receiver:ColorInt Int.darkerColor
    get() = ColorUtil.darkenColor(this)

inline val Int.colorStateList : ColorStateList
    get() = ColorStateList.valueOf(this)