package com.remax.visualnovel.widget.uitoken

import android.content.res.ColorStateList
import android.content.res.TypedArray
import android.graphics.LinearGradient
import android.graphics.Outline
import android.graphics.Shader
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.StateListDrawable
import android.os.Build
import android.util.TypedValue
import android.view.View
import android.view.ViewOutlineProvider
import android.widget.EditText
import android.widget.TextView
import androidx.annotation.StringRes
import com.remax.visualnovel.R
import com.remax.visualnovel.app.base.app.CommonApplicationProxy
import com.remax.visualnovel.extension.getIconFontType
import com.remax.visualnovel.extension.getTextFontTypeface
import com.remax.visualnovel.widget.uitoken.bean.CustomViewToken
import com.remax.visualnovel.widget.uitoken.bean.UIToken
import com.remax.visualnovel.widget.uitoken.view.UITokenEditView
import com.remax.visualnovel.widget.uitoken.view.UITokenTextView
import com.remax.visualnovel.widget.uitoken.view.UIView
import timber.log.Timber

/**
 * Created by HJW on 2022/9/1
 */

/**
 * 修改文字字体
 */
fun TextView.changeTextFont(customViewToken: CustomViewToken) {
    if (customViewToken.onlyIconFont) {
        typeface = context.getIconFontType()
    } else {
        setTokenFont(customViewToken.textUITextToken)
    }
}

/**
 * 修改文字字体和颜色
 */
fun TextView.changeTextStyle(block: CustomViewToken.() -> Unit) {
    changeTextFont(block)
    changeTextColor(block)
}

/**
 * 修改文字字体
 */
fun TextView.changeTextFont(block: CustomViewToken.() -> Unit) {
    when (this) {
        is UITokenTextView -> {
            changeTextFont(getUITokenView().apply(block))
        }

        is UITokenEditView -> {
            changeTextFont(getUITokenView().apply(block))
        }

        else -> {
            val uiToken = CustomViewToken()
            changeTextFont(uiToken.apply(block))
        }
    }
}

/**
 * 修改文字颜色
 */
fun TextView.changeTextColor(block: CustomViewToken.() -> Unit) {
    when (this) {
        is UITokenTextView -> {
            changeTextColor(getUITokenView().apply(block))
        }

        is UITokenEditView -> {
            changeTextColor(getUITokenView().apply(block))
        }

        else -> {
            val uiToken = CustomViewToken()
            changeTextColor(uiToken.apply(block))
        }
    }
}

/**
 * 修改文字颜色
 */
fun TextView.changeTextColor(@StringRes textUIColorToken: Int) {
    changeTextColor {
        this.textUIColorToken = context.getString(textUIColorToken)
    }
}

/**
 * 修改文字颜色
 */
fun TextView.changeTextColor(customViewToken: CustomViewToken) {
    customViewToken.run {
        setTokenColor(
            textUIColorToken,
            textUIPressedColorToken,
            textUIHoveredColorToken,
            textUIDisabledColorToken,
            textUIHintColorToken,
            textUILinkColorToken
        )
    }
}

/**
 * 修改阴影
 */
fun View.changeOutline(customViewToken: CustomViewToken) {
    if (customViewToken.outlineToken.isEmpty()) return
    customViewToken.outlineToken.handleUIToken(context)?.outLine?.let { out ->
        val radius = customViewToken.radiusToken.handleUIToken(context)?.size ?: 0f
        clipToOutline = false
        elevation = out.elevation
        outlineProvider = object : ViewOutlineProvider() {
            override fun getOutline(view: View, outline: Outline) {
                outline.alpha = out.alpha
                outline.setRoundRect(0, 0, view.width, view.height, radius)
                if (out.offsetX != 0 || out.offsetY != 0) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                        outlineSpotShadowColor = out.color
                    }
                    outline.offset(out.offsetX, out.offsetY)
                }
            }
        }
    }
}

/**
 * 重新覆盖圆角时，block分别设置4个角的，因为4个角已经被上一次的总radius赋值了，不会走ifEmpty了
 * 修改背景色
 */
fun View.changeBackground(block: CustomViewToken.() -> Unit) {
    when (this) {
        is UIView -> {
            changeBackground(this.getUITokenView().apply(block))
        }

        else -> {
            val uiToken = CustomViewToken()
            changeBackground(uiToken.apply(block))
        }
    }
}

/**
 * 修改背景色&圆角
 */
fun View.changeBackground(
    @StringRes backgroundUIColorToken: Int,
    @StringRes radiusToken: Int = 0,
    @StringRes topLeftRadiusToken: Int = radiusToken,
    @StringRes topRightRadiusToken: Int = radiusToken,
    @StringRes bottomRightRadiusToken: Int = radiusToken,
    @StringRes bottomLeftRadiusToken: Int = radiusToken
) {
    changeBackground(
        CustomViewToken(
            backgroundUIColorToken = context.getString(backgroundUIColorToken),
            topLeftRadiusToken = if (topLeftRadiusToken == 0) "" else context.getString(topLeftRadiusToken),
            topRightRadiusToken = if (topRightRadiusToken == 0) "" else context.getString(topRightRadiusToken),
            bottomRightRadiusToken = if (bottomRightRadiusToken == 0) "" else context.getString(bottomRightRadiusToken),
            bottomLeftRadiusToken = if (bottomLeftRadiusToken == 0) "" else context.getString(bottomLeftRadiusToken),
        )
    )
}

/**
 * 修改背景色
 */
fun View.changeBackground(customViewToken: CustomViewToken) {
    customViewToken.run {
        if (advRadius > 0 || advStrokeWidth > 0 ||
            advTopRightRadius > 0 || advTopLeftRadius > 0 ||
            advBottomLeftRadius > 0 || advBottomRightRadius > 0) {
            setBgColorDirectly(
                bgColor = advBgColor,
                radius = advRadius,
                topLeftRadius = if (advTopLeftRadius > 0F) advTopLeftRadius else advRadius,
                topRightRadius = if (advTopRightRadius > 0F) advTopRightRadius else advRadius,
                bottomRightRadius = if (advBottomRightRadius > 0F) advBottomRightRadius else advRadius,
                bottomLeftRadius = if (advBottomLeftRadius > 0F) advBottomLeftRadius else advRadius,
                strokeWidth = advStrokeWidth,
                strokeColor = advStrokeColor,
            )

        } else {
            setTokenBgColor(
                normalToken = backgroundUIColorToken,
                pressedToken = backgroundUIPressedColorToken,
                hoveredToken = backgroundUIHoveredColorToken,
                disabledToken = backgroundUIDisabledColorToken,
                radiusToken = radiusToken,
                topLeftRadiusToken = topLeftRadiusToken.ifEmpty { radiusToken },
                topRightRadiusToken = topRightRadiusToken.ifEmpty { radiusToken },
                bottomRightRadiusToken = bottomRightRadiusToken.ifEmpty { radiusToken },
                bottomLeftRadiusToken = bottomLeftRadiusToken.ifEmpty { radiusToken },
                strokeColorWidthToken = strokeUIWidthToken,
                normalStrokeColorToken = strokeUIColorToken,
                pressedStrokeColorToken = strokeUIPressedColorToken,
                hoveredStrokeColorToken = strokeUIHoveredColorToken,
                disabledStrokeColorToken = strokeUIDisabledColorToken,
                dashWidth = strokeDashWidth,
                dashGap = strokeDashGap,
            )

        }
    }
}

/**
 * 设置文字大小
 */
private fun TextView.setTokenFont(textToken: String) {
    if (textToken.isEmpty()) return
    textToken.handleUIToken(this.context)?.textFont?.run {
        Timber.d("${this@setTokenFont} setTokenFont : $this")
        val myTypeface = context.getTextFontTypeface(typeFace)
        //API 28才能直接设置字重和斜体
//        val tp = Typeface.create(myTypeface,100,true) val tp = Typeface.create(myTypeface,100,true)
        typeface = myTypeface
        if (textFontSize != 0f) {
            setTextSize(TypedValue.COMPLEX_UNIT_PX, textFontSize)
        }
        if (textLineSpace != 0f) {
            setLineSpacing(textLineSpace, 1f)
        }
    }
}

/**
 * textView 设置各种文字颜色
 */
private fun TextView.setTokenColor(
    normalToken: String,
    pressedToken: String = "",
    hoveredToken: String = "",
    disabledToken: String = "",
    hintToken: String = "",
    linkToken: String = "",
) {
    if (normalToken.isEmpty()) return
    normalToken.handleUIToken(this.context)?.run {
        when (type) {
            UIToken.FILL_COLOR -> {
                paint.shader = null
                setTextColor(this.color)
            }

            UIToken.LINEAR_GRADIENT -> {
                val getText = text.toString()
                val x0 = 0f
                var x1 = 0f
                val y0 = 0f
                var y1 = 0f
                when (deg) {
                    //从左到右
                    resources.getString(R.string.glo_deg_ltr) -> {
                        x1 = paint.measureText(getText)
                    }
                    //从上到下
                    resources.getString(R.string.glo_deg_ttb) -> {
                        y1 = textSize
                    }
                    //从左上到右下
                    resources.getString(R.string.glo_deg_lttrb) -> {
                        x1 = paint.measureText(getText)
                        y1 = textSize
                    }
                }
                val gradient = LinearGradient(
                    x0,
                    y0,
                    x1,
                    y1,
                    colors,
                    null,
                    Shader.TileMode.CLAMP
                )
                paint.shader = gradient
            }
        }
    }
    //设置hint颜色
    hintToken.handleUIToken(this.context)?.run {
        if (this.color != 0) {
            setHintTextColor(this.color)
        }
    }
    //设置link颜色
    linkToken.handleUIToken(this.context)?.run {
        if (this.color != 0) {
            setLinkTextColor(this.color)
        }
    }
    if (disabledToken.isNotEmpty() || hoveredToken.isNotEmpty() || pressedToken.isNotEmpty()) {
        val disabledColor = disabledToken.handleUIToken(this.context)?.color ?: 0
        val hoveredColor = hoveredToken.handleUIToken(this.context)?.color ?: 0
        val pressColor = pressedToken.handleUIToken(this.context)?.color ?: 0
        val colorList = createColorStateList(disabledColor, hoveredColor, pressColor, currentTextColor)
        setTextColor(colorList)
    }
}

private fun createColorStateList(disabled: Int, hovered: Int, pressed: Int, normal: Int): ColorStateList {
    val colors = intArrayOf(
        if (pressed != 0) pressed else normal,
        if (hovered != 0) hovered else normal,
        normal,
        if (disabled != 0) disabled else normal
    )
    val states = arrayOfNulls<IntArray>(4)
    states[0] = intArrayOf(android.R.attr.state_pressed, android.R.attr.state_enabled)
    states[1] = intArrayOf(android.R.attr.state_hovered, android.R.attr.state_enabled)
    states[2] = intArrayOf(android.R.attr.state_enabled)
    states[3] = intArrayOf()
    return ColorStateList(states, colors)
}


/**
 * 设置背景色
 */
private fun View.setTokenBgColor(
    normalToken: String,
    pressedToken: String = "",
    hoveredToken: String = "",
    disabledToken: String = "",
    radiusToken: String = "",
    topLeftRadiusToken: String = radiusToken,
    topRightRadiusToken: String = radiusToken,
    bottomRightRadiusToken: String = radiusToken,
    bottomLeftRadiusToken: String = radiusToken,
    strokeColorWidthToken: String = "",
    normalStrokeColorToken: String = "",
    pressedStrokeColorToken: String = "",
    hoveredStrokeColorToken: String = "",
    disabledStrokeColorToken: String = "",
    dashWidth: Float = 0f,
    dashGap: Float = 0f,
) {
    if (normalToken.isEmpty()) return
    val resDrawable = StateListDrawable()
    if (pressedToken.isNotEmpty()) {
        getGradientDrawable(
            pressedToken,
            topLeftRadiusToken,
            topRightRadiusToken,
            bottomRightRadiusToken,
            bottomLeftRadiusToken,
            strokeColorWidthToken,
            pressedStrokeColorToken,
            dashWidth,
            dashGap
        ).let { pressedDrawable ->
            resDrawable.addState(
                intArrayOf(android.R.attr.state_pressed, android.R.attr.state_enabled),
                pressedDrawable
            )
        }
    }

    if (hoveredToken.isNotEmpty()) {
        getGradientDrawable(
            hoveredToken,
            topLeftRadiusToken,
            topRightRadiusToken,
            bottomRightRadiusToken,
            bottomLeftRadiusToken,
            strokeColorWidthToken,
            hoveredStrokeColorToken,
            dashWidth,
            dashGap
        ).let { hoveredDrawable ->
            if (this is EditText) {
                resDrawable.addState(
                    intArrayOf(android.R.attr.state_focused, android.R.attr.state_enabled),
                    hoveredDrawable
                )
            }
            resDrawable.addState(
                intArrayOf(android.R.attr.state_hovered, android.R.attr.state_enabled),
                hoveredDrawable
            )
        }
    }

    val normalDrawable = getGradientDrawable(
        normalToken,
        topLeftRadiusToken,
        topRightRadiusToken,
        bottomRightRadiusToken,
        bottomLeftRadiusToken,
        strokeColorWidthToken,
        normalStrokeColorToken,
        dashWidth,
        dashGap
    )
    resDrawable.addState(intArrayOf(android.R.attr.state_enabled), normalDrawable)

    if (disabledToken.isNotEmpty()) {
        val disabledDrawable = getGradientDrawable(
            disabledToken,
            topLeftRadiusToken,
            topRightRadiusToken,
            bottomRightRadiusToken,
            bottomLeftRadiusToken,
            strokeColorWidthToken,
            disabledStrokeColorToken,
            dashWidth,
            dashGap
        )
        resDrawable.addState(intArrayOf(), disabledDrawable)
    } else {
        resDrawable.addState(intArrayOf(), normalDrawable)
    }


    background = resDrawable
}

fun getGradientDrawableOrientation(deg: String?): GradientDrawable.Orientation {
    val resources = CommonApplicationProxy.application.resources
    return when (deg) {
        //从左到右
        resources.getString(R.string.glo_deg_ltr) -> {
            GradientDrawable.Orientation.LEFT_RIGHT
        }
        //从上到下
        resources.getString(R.string.glo_deg_ttb) -> {
            GradientDrawable.Orientation.TOP_BOTTOM
        }
        //从左上到右下
        resources.getString(R.string.glo_deg_lttrb) -> {
            GradientDrawable.Orientation.TL_BR
        }

        else -> {
            GradientDrawable.Orientation.LEFT_RIGHT
        }
    }
}

/**
 * 获取带颜色的Drawable
 */
fun View.getGradientDrawable(
    bgColorToken: String,
    topLeftRadiusToken: String = "",
    topRightRadiusToken: String = "",
    bottomRightRadiusToken: String = "",
    bottomLeftRadiusToken: String = "",
    strokeWidthToken: String = "",
    strokeColorToken: String = "",
    dashWidth: Float = 0f,  // 虚线的长度
    dashGap: Float = 0f, // 虚线的间距，0为实线
): Drawable {
    val gradientDrawable = GradientDrawable()
    gradientDrawable.shape = GradientDrawable.RECTANGLE
    bgColorToken.handleUIToken(this.context)?.run {
        when (type) {
            UIToken.FILL_COLOR -> {
                gradientDrawable.setColor(color)
            }

            UIToken.LINEAR_GRADIENT -> {
                gradientDrawable.orientation = getGradientDrawableOrientation(deg)
                gradientDrawable.colors = colors
            }
        }
    }
    val swToken = strokeWidthToken.handleUIToken(this.context)
    if (swToken != null) {
        if (strokeColorToken.isNotEmpty()) {
            strokeColorToken.handleUIToken(this.context)?.let { scToken ->
                gradientDrawable.setStroke(swToken.size.toInt(), scToken.color, dashWidth, dashGap)
            }
        }
    } else {
        gradientDrawable.setStroke(0, 0)
    }

    val topLeftRadius = topLeftRadiusToken.handleUIToken(this.context)?.size ?: 0f
    val topRightRadius = topRightRadiusToken.handleUIToken(this.context)?.size ?: 0f
    val bottomRightRadius = bottomRightRadiusToken.handleUIToken(this.context)?.size ?: 0f
    val bottomLeftRadius = bottomLeftRadiusToken.handleUIToken(this.context)?.size ?: 0f
    //左上、右上、右下、左下的圆角半径
    gradientDrawable.cornerRadii = floatArrayOf(
        topLeftRadius,
        topLeftRadius,
        topRightRadius,
        topRightRadius,
        bottomRightRadius,
        bottomRightRadius,
        bottomLeftRadius,
        bottomLeftRadius
    )
    return gradientDrawable
}





//*------------------------ new added ------------------------*//

/**
 * 设置背景色
 */
fun View.setBgColorDirectly(
    bgColor: Int = 0,
    radius: Float = 0F,
    topLeftRadius: Float = radius,
    topRightRadius: Float = radius,
    bottomRightRadius: Float = radius,
    bottomLeftRadius: Float = radius,
    strokeWidth: Float = 0F,
    strokeColor: Int = -1
) {
    val resDrawable = StateListDrawable()
    val normalDrawable = getGradientDrawableDirectly(
        bgColor,
        topLeftRadius,
        topRightRadius,
        bottomRightRadius,
        bottomLeftRadius,
        strokeWidth,
        strokeColor
    )
    resDrawable.addState(intArrayOf(android.R.attr.state_enabled), normalDrawable)
    background = resDrawable
}


fun View.getGradientDrawableDirectly(
    bgColor: Int = 0,
    topLeftRadius: Float = 0F,
    topRightRadius: Float = 0F,
    bottomRightRadius: Float = 0F,
    bottomLeftRadius: Float = 0F,
    strokeWidth: Float = 0F,
    strokeColor: Int = -1
): Drawable {
    val gradientDrawable = GradientDrawable()
    gradientDrawable.shape = GradientDrawable.RECTANGLE
    gradientDrawable.setColor(bgColor)

    if (strokeWidth > 0) {
        gradientDrawable.setStroke(strokeWidth.toInt(), strokeColor)
    }

    gradientDrawable.cornerRadii = floatArrayOf(
        topLeftRadius,
        topLeftRadius,
        topRightRadius,
        topRightRadius,
        bottomRightRadius,
        bottomRightRadius,
        bottomLeftRadius,
        bottomLeftRadius
    )
    return gradientDrawable
}

