package com.example.epl498_labs.ui.calculator;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import net.objecthunter.exp4j.Expression;
import net.objecthunter.exp4j.ExpressionBuilder;
import net.objecthunter.exp4j.function.Function;

import com.example.epl498_labs.R;

public class CalculatorFragment extends Fragment {

    private TextView tvDisplay;
    private StringBuilder expression = new StringBuilder();
    // Flag to clear display after pressing "="
    private boolean isNewInput = false;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_calculator, container, false);

        tvDisplay = view.findViewById(R.id.tv_display);

        // Digit buttons between 0-9
        int[] digitIds = {R.id.btn_0, R.id.btn_1, R.id.btn_2, R.id.btn_3, R.id.btn_4,
                R.id.btn_5, R.id.btn_6, R.id.btn_7, R.id.btn_8, R.id.btn_9};

        View.OnClickListener digitListener = v -> {
            Button b = (Button) v;
            // If we just finished an operation, start fresh
            if (isNewInput) {
                expression.setLength(0);
                isNewInput = false;
            }
            expression.append(b.getText().toString());
            tvDisplay.setText(expression.toString());
        };

        for (int id : digitIds) {
            view.findViewById(id).setOnClickListener(digitListener);
        }

        // Set on click listeners for each button
        // Which in this case are the operators, parentheses and dot
        view.findViewById(R.id.btn_add).setOnClickListener(v -> addSymbol("+"));
        view.findViewById(R.id.btn_sub).setOnClickListener(v -> addSymbol("-"));
        view.findViewById(R.id.btn_open).setOnClickListener(v -> addSymbol("("));
        view.findViewById(R.id.btn_close).setOnClickListener(v -> addSymbol(")"));
        view.findViewById(R.id.btn_dot).setOnClickListener(v -> addSymbol("."));

        // Log
        view.findViewById(R.id.btn_log).setOnClickListener(v -> addSymbol("log("));


        // Equal
        view.findViewById(R.id.btn_equal).setOnClickListener(v -> evaluateExpression());

        // Delete last character
        view.findViewById(R.id.btn_del).setOnClickListener(v -> {
            if (expression.length() > 0) {
                expression.deleteCharAt(expression.length() - 1);
                tvDisplay.setText(expression.length() > 0 ? expression.toString() : "0");
            }
        });

        // Clear all
        view.findViewById(R.id.btn_clear).setOnClickListener(v -> {
            expression.setLength(0);
            tvDisplay.setText("0");
            isNewInput = false;
        });

        return view;
    }

    // Returns true if the current number already has a dot
    private boolean currentNumberContainsDot() {
        int i = expression.length() - 1;
        while (i >= 0) {
            char c = expression.charAt(i);
            if (c == '.') return true; // found a dot
            if (!Character.isDigit((c))) break; // reached an operator
            i--;
        }
        return false;
    }

    private void addSymbol(String s) {
        if (isNewInput) {
            isNewInput = false;
        }
        expression.append(s);
        tvDisplay.setText(expression.toString());
    }

    private void evaluateExpression() {
        if (expression.length() == 0) return;

        try {
            //Expression exp = new ExpressionBuilder(expression.toString()).build();

            // Custom logarithm function with base 10
            Function log = new Function("log", 1) {
                @Override
                public double apply(double... args) {
                    double value = args[0];
                    return Math.log(value) / Math.log(10);
                }
            };
            /**
             * Build and evaluate the expression
             * In the case of having multiple functions we would register them comma-separated, like this:
             * .functions(logn, otherFunction, anotherFunction)
             */

            Expression exp = new ExpressionBuilder(expression.toString())
                    .functions(log) // register custom functions
                    .build();

            // the exp.evaluate() performs the operation for us :)
            double result = exp.evaluate();

            // Round to a fixed number of decimals so that the calculation of double
            // numbers is done correct (this is an issue with Java and exp4j)
            result = Math.round(result * 1_000_000_000d) / 1_000_000_000d;
            tvDisplay.setText(String.valueOf(result));
            expression.setLength(0);
            expression.append(result);
        } catch (Exception e) {
            tvDisplay.setText("The operation is not valid!");
            expression.setLength(0);
        }
        isNewInput = true;
    }
}