package com.rugvedsarika.areacalc

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import java.text.DecimalFormat

class MainViewModel : ViewModel() {

    private val _inputValue = MutableLiveData<String>("")
    val inputValue: LiveData<String> = _inputValue
    
    private val _rateValue = MutableLiveData<String>("")
    val rateValue: LiveData<String> = _rateValue

    private val _fromUnit = MutableLiveData<AreaUnit>(AreaUnit.SQUARE_METER)
    val fromUnit: LiveData<AreaUnit> = _fromUnit

    private val _toUnit = MutableLiveData<AreaUnit>(AreaUnit.SQUARE_FOOT)
    val toUnit: LiveData<AreaUnit> = _toUnit

    private val _result = MutableLiveData<String>("0")
    val result: LiveData<String> = _result
    
    private val _totalPrice = MutableLiveData<String>("0")
    val totalPrice: LiveData<String> = _totalPrice

    private val decimalFormat = DecimalFormat("#.####")

    fun onInputValueChanged(value: String) {
        _inputValue.value = value
        calculate()
    }
    
    fun onRateValueChanged(value: String) {
        _rateValue.value = value
        calculatePrice()
    }

    fun setFromUnit(unit: AreaUnit) {
        _fromUnit.value = unit
        calculate()
    }

    fun setToUnit(unit: AreaUnit) {
        _toUnit.value = unit
        calculate()
    }

    fun swapUnits() {
        val currentFrom = _fromUnit.value
        val currentTo = _toUnit.value
        _fromUnit.value = currentTo
        _toUnit.value = currentFrom
        calculate()
    }

    private fun calculate() {
        val inputStr = _inputValue.value
        val input = evaluateExpression(inputStr)
        val from = _fromUnit.value
        val to = _toUnit.value

        if (input != null && from != null && to != null) {
            val convertedValue = AreaUnit.convert(input, from, to)
            _result.value = decimalFormat.format(convertedValue)
            calculatePrice(input) // Recalculate price when area changes
        } else {
            _result.value = "0"
            _totalPrice.value = "0"
        }
    }
    
    private fun calculatePrice(areaValue: Double? = null) {
        val area = areaValue ?: evaluateExpression(_inputValue.value)
        val rate = _rateValue.value?.toDoubleOrNull()
        
        if (area != null && rate != null) {
            val price = area * rate
            _totalPrice.value = decimalFormat.format(price)
        } else {
            _totalPrice.value = "0"
        }
    }
    
    // Robust expression parser for +, -, *, / with correct precedence
    private fun evaluateExpression(expression: String?): Double? {
        if (expression.isNullOrEmpty()) return null
        
        // Remove spaces
        val cleanExpr = expression.replace(" ", "")
        
        // Check for invalid characters (only digits, ., +, -, *, / allowed)
        if (!cleanExpr.matches(Regex("^[0-9.+\\-*/]+$"))) return null

        try {
            // Level 1: Split by '+'
            val plusParts = cleanExpr.split("+")
            var sum = 0.0
            for (plusPart in plusParts) {
                // Level 2: Split by '-'
                // Note: The first part is positive, subsequent parts are subtracted.
                // However, split("-") on "a-b-c" gives ["a", "b", "c"].
                // So result is eval(a) - eval(b) - eval(c).
                val minusParts = plusPart.split("-")
                var minusResult = evaluateTerm(minusParts[0])
                
                for (i in 1 until minusParts.size) {
                    val partVal = evaluateTerm(minusParts[i])
                    minusResult -= partVal
                }
                sum += minusResult
            }
            return sum
        } catch (e: Exception) {
            return null
        }
    }
    
    // Level 3 & 4: Handle * and /
    private fun evaluateTerm(term: String): Double {
        if (term.isEmpty()) return 0.0
        
        val mulParts = term.split("*")
        var mulResult = evaluateFactor(mulParts[0])
        
        for (i in 1 until mulParts.size) {
            val partVal = evaluateFactor(mulParts[i])
            mulResult *= partVal
        }
        return mulResult
    }
    
    private fun evaluateFactor(factor: String): Double {
        if (factor.isEmpty()) return 0.0
        
        val divParts = factor.split("/")
        var divResult = divParts[0].toDoubleOrNull() ?: 0.0
        
        for (i in 1 until divParts.size) {
            val partVal = divParts[i].toDoubleOrNull() ?: 1.0 // Avoid div by zero causing issues if possible, though infinity is fine
            if (partVal != 0.0) {
                divResult /= partVal
            }
        }
        return divResult
    }
}
