package org.foxarmy.barcodescannerforemployees.views

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.os.Bundle
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.startActivity
import androidx.core.graphics.blue
import androidx.core.graphics.green
import androidx.core.graphics.red
import androidx.core.math.MathUtils.clamp
import org.foxarmy.barcodescannerforemployees.*
import org.foxarmy.barcodescannerforemployees.activities.FullscreenActivity
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
import org.foxarmy.barcodescannerforemployees.dataclasses.Product
import java.io.File
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
import kotlin.concurrent.thread

class ProductView: LinearLayout {
    var product: Product = Product()
    var isProductSelected = false
    private lateinit var activity: Activity

    private lateinit var productImageView: ImageView
    private lateinit var productNameTextView: TextView
    private lateinit var productNetWeightTextView: TextView
    private lateinit var productAmountTextView: TextView
    private lateinit var productCategoryView: TextView
    private lateinit var productLifeSpan: TextView
    private lateinit var productFreshnessTextView: TextView

    private var backgroundColor: Int = 0xffffff
    private var strokeColor: Int = 0x000000
    private lateinit var outline: GradientDrawable

    constructor(context: Context, a: AttributeSet) : super(context, a) {
        activity = getActivity(context)!!
        val inflater: LayoutInflater = activity.layoutInflater
        inflater.inflate(R.layout.product_view, this)
    }

    @RequiresApi(Build.VERSION_CODES.O)
    constructor(activity: Activity, context: Context, product: Product) : super(context) {
        this.product = product
        this.activity = activity
        val inflater: LayoutInflater = activity.layoutInflater
        inflater.inflate(R.layout.product_view, this)

        productImageView = findViewById(R.id.productPicture)
        productNameTextView = findViewById(R.id.productNameView)
        productNetWeightTextView = findViewById(R.id.productNetWeightView)
        productAmountTextView = findViewById(R.id.amountView)
        productCategoryView = findViewById(R.id.categoryView)
        productLifeSpan = findViewById(R.id.dateSpan)
        productFreshnessTextView = findViewById(R.id.freshnessPercentTextView)

        findViewById<ConstraintLayout>(R.id.productLayout).setOnLongClickListener {
            isProductSelected = !isProductSelected
            updateStroke()
            true
        }

        productImageView.setOnClickListener {
            val fullscreenIntent = Intent(activity, FullscreenActivity::class.java)
            val extras = Bundle()
            val abstractProduct = DBStorageController(context).findAbstractProductById(DBStorageController(context).readableDatabase, product.abstractProductId)
            extras.putString("imagehash", abstractProduct!!.imageHash)
            fullscreenIntent.putExtras(extras)
            startActivity(context, fullscreenIntent, extras)
        }

        update()
    }

    @RequiresApi(Build.VERSION_CODES.O)
    fun update () {
        val linkedAbstractProduct: AbstractProduct = DBStorageController(activity).findAbstractProductById(DBStorageController(activity).readableDatabase, product.abstractProductId)!!

        val thumbnailsDir = File(activity.cacheDir, "thumbnails")
        thumbnailsDir.mkdirs()
        val pictureFile = File(thumbnailsDir, "${linkedAbstractProduct.imageHash}.webp")
        val imageUri = getImageUri(activity, pictureFile)
        productImageView.setImageURI(imageUri)
        productImageView.rotation = 90f

        productNameTextView.text = linkedAbstractProduct.name
        productNetWeightTextView.text = linkedAbstractProduct.netWeight.toString()
        productAmountTextView.text = product.amount.toString()
        productCategoryView.text = DBStorageController(activity).getCategoryNameById(DBStorageController(activity).readableDatabase, linkedAbstractProduct.category)
        productLifeSpan.text = "${SimpleDateFormat("dd.MM.yyyy").format(Date(product.dateOfProduction*1000))}-${SimpleDateFormat("dd.MM.yyyy").format(Date(product.dateOfExpiry*1000))}"
        productFreshnessTextView.text =
        if (product.freshness == Double.NEGATIVE_INFINITY || product.freshness == Double.POSITIVE_INFINITY) {
            "Expired"
        } else {
            "${DecimalFormat("#.#").format(product.freshness*100)}%"
        }

        updateStroke()
    }

    @RequiresApi(Build.VERSION_CODES.O)
    fun updateStroke() {
         if (isProductSelected) {
             this.background = ContextCompat.getDrawable(context, R.drawable.outline_selected)
        } else {
             if (product.id != 0) {
                 thread {
                     this.outline = GradientDrawable()
                     backgroundColor = evaluateColor()
                     strokeColor = darkenColor(backgroundColor, 0.25) // (backgroundColor and 0xfefefe ) shr 1
                     this.outline.setColor(backgroundColor)
                     this.outline.setStroke(4, strokeColor)
                     this.outline.alpha = 84
                     this.background = outline
                 }
             } else {
                 this.background = ContextCompat.getDrawable(context, R.drawable.outline)
             }
        }
    }

    @RequiresApi(Build.VERSION_CODES.O)
    fun evaluateColor(): Int {
        val freshnessPercentage = calculateProductFreshness(product.dateOfProduction, product.dateOfExpiry)
        return calculateFreshnessGradient(freshnessPercentage)
    }

    fun calculateFreshnessGradient(percentage: Double): Int {
        val startColor = ContextCompat.getColor(context, if (percentage > 0.5) R.color.full_freshness else R.color.half_freshness)
        val endColor = ContextCompat.getColor(context, if (percentage > 0.5) R.color.half_freshness else R.color.expired_freshness)

        val gradientPosition = 1 - if (percentage > 0.5) (percentage - 0.5) * 2 else percentage * 2

        val red = clamp((startColor.red + gradientPosition * (endColor.red - startColor.red )).toInt(), 0, 255)
        val green = clamp((startColor.green  + gradientPosition * (endColor.green - startColor.green)).toInt(), 0, 255)
        val blue = clamp((startColor.blue + gradientPosition * (endColor.blue - startColor.blue)).toInt(), 0, 255)

        var redHex = Integer.toHexString(red)
        if (redHex.length == 1) redHex = "0$redHex"

        var greenHex = Integer.toHexString(green)
        if (greenHex.length == 1) greenHex = "0$greenHex"

        var blueHex = Integer.toHexString(blue)
        if (blueHex.length == 1 ) blueHex = "0$blueHex"


        val colorString = "#$redHex$greenHex$blueHex"
        return Color.parseColor(colorString)
    }

    @RequiresApi(Build.VERSION_CODES.O)
    fun darkenColor(color: Int, darkPercent: Double) : Int {
        val c = Color.valueOf(color)

        val red = c.red() * (1 - darkPercent)
        val green = c.green() * (1 - darkPercent)
        val blue = c.blue() * (1 - darkPercent)

        return Color.rgb(red.toFloat(), green.toFloat(), blue.toFloat())
    }
}