/*
 * Copyright 2025 Circle Internet Group, Inc. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cybavo.reactnative.wallet.service.view;

import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.RippleDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Build;
import android.util.StateSet;
import android.view.View;

import com.cybavo.reactnative.wallet.service.R;
import com.cybavo.wallet.service.view.NumericPinCodeInputView;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.ViewDefaults;

public class ButtonPropertyHolder {

    final static int UNDEFINED_INT = Integer.MIN_VALUE;
    final static float UNDEFINED_FLOAT = Float.MIN_VALUE;

    private final static int DEFAULT_TEXT_COLOR = Color.BLACK;
    private final static int DEFAULT_BACKGROUND_COLOR = Color.TRANSPARENT;
    private final static int DEFAULT_BORDER_COLOR = Color.TRANSPARENT;
    private final static float DEFAULT_TEXT_SIZE = PixelUtil.toPixelFromSP(ViewDefaults.FONT_SIZE_SP);

    private final static int[] STATE_PRESSED = { android.R.attr.state_pressed };
    private final static int[] STATE_DISABLED = { -android.R.attr.state_enabled };
    private final static int[] STATE_BASE = StateSet.WILD_CARD;

    // regular button
    private int width = ButtonPropertyHolder.UNDEFINED_INT;
    private int height = ButtonPropertyHolder.UNDEFINED_INT;
    private int borderRadius = ButtonPropertyHolder.UNDEFINED_INT;
    private int borderWidth = ButtonPropertyHolder.UNDEFINED_INT;
    private float textSize = UNDEFINED_FLOAT;
    private Integer rippleColor;

    private Integer backgroundColor;
    private Integer backgroundColorPressed;
    private Integer backgroundColorDisabled;

    private Integer borderColor;
    private Integer borderColorPressed;
    private Integer borderColorDisabled;

    private Integer textColor;
    private Integer textColorPressed;
    private Integer textColorDisabled;

    // backspace button
    private int backspaceWidth = ButtonPropertyHolder.UNDEFINED_INT;
    private int backspaceHeight = ButtonPropertyHolder.UNDEFINED_INT;
    private int backspaceBorderRadius = ButtonPropertyHolder.UNDEFINED_INT;
    private int backspaceBorderWidth = ButtonPropertyHolder.UNDEFINED_INT;
    private float backspaceTextSize = UNDEFINED_FLOAT;
    private Integer backspaceRippleColor;

    private Integer backspaceBackgroundColor;
    private Integer backspaceBackgroundColorPressed;
    private Integer backspaceBackgroundColorDisabled;

    private Integer backspaceBorderColor;
    private Integer backspaceBorderColorPressed;
    private Integer backspaceBorderColorDisabled;

    private Integer backspaceTextColor;
    private Integer backspaceTextColorPressed;
    private Integer backspaceTextColorDisabled;

    // regular buttons
    static void setWidth(NumericPinCodeInputView view, int width) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.width = width;
        props.apply(view);
    }

    static void setHeight(NumericPinCodeInputView view, int height) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.height = height;
        props.apply(view);
    }

    static void setBorderRadius(NumericPinCodeInputView view, int borderRadius) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.borderRadius = borderRadius;
        props.apply(view);
    }

    static void setBorderWidth(NumericPinCodeInputView view, int borderWidth) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.borderWidth = borderWidth;
        props.apply(view);
    }

    static void setTextSize(NumericPinCodeInputView view, float textSize) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.textSize = textSize;
        props.apply(view);
    }

    static void setBackgroundColor(NumericPinCodeInputView view, Integer backgroundColor) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backgroundColor = backgroundColor;
        props.apply(view);
    }

    static void setBackgroundColorPressed(NumericPinCodeInputView view, Integer backgroundColorPressed) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backgroundColorPressed = backgroundColorPressed;
        props.apply(view);
    }

    static void setBackgroundColorDisabled(NumericPinCodeInputView view, Integer backgroundColorDisabled) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backgroundColorDisabled = backgroundColorDisabled;
        props.apply(view);
    }

    static void setBorderColor(NumericPinCodeInputView view, Integer borderColor) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.borderColor = borderColor;
        props.apply(view);
    }

    static void setBorderColorPressed(NumericPinCodeInputView view, Integer borderColorPressed) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.borderColorPressed = borderColorPressed;
        props.apply(view);
    }

    static void setBorderColorDisabled(NumericPinCodeInputView view, Integer borderColorDisabled) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.borderColorDisabled = borderColorDisabled;
        props.apply(view);
    }

    static void setTextColor(NumericPinCodeInputView view, Integer textColor) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.textColor = textColor;
        props.apply(view);
    }

    static void setTextColorPressed(NumericPinCodeInputView view, Integer textColorPressed) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.textColorPressed = textColorPressed;
        props.apply(view);
    }

    static void setTextColorDisabled(NumericPinCodeInputView view, Integer textColorDisabled) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.textColorDisabled = textColorDisabled;
        props.apply(view);
    }

    static void setRippleColor(NumericPinCodeInputView view, Integer rippleColor) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.rippleColor = rippleColor;
        props.apply(view);
    }

    // Backspace
    static void setBackspaceWidth(NumericPinCodeInputView view, int width) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceWidth = width;
        props.apply(view);
    }

    static void setBackspaceHeight(NumericPinCodeInputView view, int height) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceHeight = height;
        props.apply(view);
    }

    static void setBackspaceBorderRadius(NumericPinCodeInputView view, int borderRadius) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceBorderRadius = borderRadius;
        props.apply(view);
    }

    static void setBackspaceBorderWidth(NumericPinCodeInputView view, int borderWidth) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceBorderWidth = borderWidth;
        props.apply(view);
    }

    static void setBackspaceTextSize(NumericPinCodeInputView view, float textSize) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceTextSize = textSize;
        props.apply(view);
    }

    static void setBackspaceBackgroundColor(NumericPinCodeInputView view, Integer backgroundColor) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceBackgroundColor = backgroundColor;
        props.apply(view);
    }

    static void setBackspaceBackgroundColorPressed(NumericPinCodeInputView view, Integer backgroundColorPressed) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceBackgroundColorPressed = backgroundColorPressed;
        props.apply(view);
    }

    static void setBackspaceBackgroundColorDisabled(NumericPinCodeInputView view, Integer backgroundColorDisabled) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceBackgroundColorDisabled = backgroundColorDisabled;
        props.apply(view);
    }

    static void setBackspaceBorderColor(NumericPinCodeInputView view, Integer borderColor) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceBorderColor = borderColor;
        props.apply(view);
    }

    static void setBackspaceBorderColorPressed(NumericPinCodeInputView view, Integer borderColorPressed) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceBorderColorPressed = borderColorPressed;
        props.apply(view);
    }

    static void setBackspaceBorderColorDisabled(NumericPinCodeInputView view, Integer borderColorDisabled) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceBorderColorDisabled = borderColorDisabled;
        props.apply(view);
    }

    static void setBackspaceTextColor(NumericPinCodeInputView view, Integer textColor) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceTextColor = textColor;
        props.apply(view);
    }

    static void setBackspaceTextColorPressed(NumericPinCodeInputView view, Integer textColorPressed) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceTextColorPressed = textColorPressed;
        props.apply(view);
    }

    static void setBackspaceTextColorDisabled(NumericPinCodeInputView view, Integer textColorDisabled) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceTextColorDisabled = textColorDisabled;
        props.apply(view);
    }

    static void setBackspaceRippleColor(NumericPinCodeInputView view, Integer rippleColor) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);
        props.backspaceRippleColor = rippleColor;
        props.apply(view);
    }

    private Drawable getBackgroundDrawable() {
        StateListDrawable drawable = new StateListDrawable();

        int bgBorderRadius = getValue(borderRadius, 0);
        int bgBorderWidth = getValue(borderWidth, 0);
        int bgWidth = getValue(width, 0);
        int bgHeight = getValue(height, 0);

        int color = getColor(backgroundColor, DEFAULT_BACKGROUND_COLOR);
        int colorPressed = getColor(backgroundColorPressed, backgroundColor, DEFAULT_BACKGROUND_COLOR);
        int colorDisabled = getColor(backgroundColorDisabled, backgroundColor, DEFAULT_BACKGROUND_COLOR);

        int colorBorder = getColor(borderColor, DEFAULT_BORDER_COLOR, DEFAULT_BORDER_COLOR);
        int colorBorderPressed = getColor(borderColorPressed, borderColor, DEFAULT_BORDER_COLOR);
        int colorBorderDisabled = getColor(borderColorDisabled, borderColor, DEFAULT_BORDER_COLOR);

        drawable.addState(STATE_PRESSED, makeDrawable(bgWidth, bgHeight, colorPressed, bgBorderRadius, bgBorderWidth, colorBorderPressed));
        drawable.addState(STATE_DISABLED, makeDrawable(bgWidth, bgHeight, colorDisabled, bgBorderRadius, bgBorderWidth, colorBorderDisabled));
        drawable.addState(STATE_BASE, makeDrawable(bgWidth, bgHeight, color, bgBorderRadius, bgBorderWidth, colorBorder));

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            int ripple = getColor(rippleColor, Color.TRANSPARENT);
            if (ripple != Color.TRANSPARENT) {
                return new RippleDrawable(ColorStateList.valueOf(ripple), drawable, null);
            }
        }

        return drawable;
    }

    private Drawable getBackspaceBackgroundDrawable() {
        StateListDrawable drawable = new StateListDrawable();

        int bgWidth = getValue(backspaceWidth, width);
        int bgHeight = getValue(backspaceHeight, height);

        int bgBorderRadius = getValue(backspaceBorderRadius, borderRadius);
        int bgBorderWidth = getValue(backspaceBorderWidth, borderWidth);

        int color = getColor(backspaceBackgroundColor,
                backgroundColor, DEFAULT_BACKGROUND_COLOR);
        int colorPressed = getColor(backspaceBackgroundColorPressed, backspaceBackgroundColor,
                backgroundColorPressed, backgroundColor, DEFAULT_BACKGROUND_COLOR);
        int colorDisabled = getColor(backspaceBackgroundColorDisabled, backspaceBackgroundColor,
                backgroundColorDisabled, backgroundColor, DEFAULT_BACKGROUND_COLOR);

        int colorBorder = getColor(backspaceBorderColor,
                borderColor, DEFAULT_BORDER_COLOR, DEFAULT_BORDER_COLOR);
        int colorBorderPressed = getColor(backspaceBorderColorPressed, backspaceBorderColor,
                borderColorPressed, borderColor, DEFAULT_BORDER_COLOR);
        int colorBorderDisabled = getColor(backspaceBorderColorDisabled, backspaceBorderColor,
                borderColorDisabled, borderColor, DEFAULT_BORDER_COLOR);

        drawable.addState(STATE_PRESSED, makeDrawable(bgWidth, bgHeight, colorPressed, bgBorderRadius, bgBorderWidth, colorBorderPressed));
        drawable.addState(STATE_DISABLED, makeDrawable(bgWidth, bgHeight, colorDisabled, bgBorderRadius, bgBorderWidth, colorBorderDisabled));
        drawable.addState(STATE_BASE, makeDrawable(bgWidth, bgHeight, color, bgBorderRadius, bgBorderWidth, colorBorder));

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            int ripple = getColor(backspaceRippleColor, rippleColor, Color.TRANSPARENT);
            if (ripple != Color.TRANSPARENT) {
                return new RippleDrawable(ColorStateList.valueOf(ripple), drawable, null);
            }
        }

        return drawable;
    }

    private ColorStateList getTextColor() {
        int[][] states = {
                STATE_PRESSED,
                STATE_DISABLED,
                STATE_BASE,
        };
        int[] colors = {
                getColor(textColorPressed, textColor, DEFAULT_TEXT_COLOR),
                getColor(textColorDisabled, textColor, DEFAULT_TEXT_COLOR),
                getColor(textColor, DEFAULT_TEXT_COLOR),
        };
        return new ColorStateList(states, colors);
    }

    private ColorStateList getBackspaceTextColor() {
        int[][] states = {
                STATE_PRESSED,
                STATE_DISABLED,
                STATE_BASE,
        };
        int[] colors = {
                getColor(backspaceTextColorPressed, backspaceTextColor, textColorPressed, textColor, DEFAULT_TEXT_COLOR),
                getColor(backspaceTextColorDisabled, backspaceTextColor, textColorDisabled, textColor, DEFAULT_TEXT_COLOR),
                getColor(backspaceTextColor, textColor, DEFAULT_TEXT_COLOR),
        };
        return new ColorStateList(states, colors);
    }

    private float getTextSize() {
        return getValue(textSize, DEFAULT_TEXT_SIZE);
    }

    private float getBackspaceTextSize() {
        return  getValue(backspaceTextSize, textSize, DEFAULT_TEXT_SIZE);
    }

    private static int getColor(Integer... fallbacks) {
        for (Integer color : fallbacks) {
            if (color != null) {
                return color;
            }
        }
        return Color.TRANSPARENT;
    }

    private static int getValue(int... fallbacks) {
        for (int pref : fallbacks) {
            if (pref != UNDEFINED_INT) {
                return pref;
            }
        }
        return 0;
    }

    private static float getValue(float... fallbacks) {
        for (float pref : fallbacks) {
            if (pref != UNDEFINED_FLOAT) {
                return pref;
            }
        }
        return 0;
    }

    private static Drawable makeDrawable(int width, int height, int color, float borderRadius, int borderWidth, int borderColor) {
        GradientDrawable drawable = new GradientDrawable();
        drawable.setSize(width, height);
        drawable.setColor(color);
        drawable.setCornerRadius(borderRadius);
        drawable.setStroke(borderWidth, borderColor);
        return drawable;
    }

    private void apply(NumericPinCodeInputView view) {
        ButtonPropertyHolder props = ButtonPropertyHolder.get(view);

        // normal button
        view.setButtonTextAppearance(
                props.getTextColor(),
                props.getTextSize(),
                Typeface.DEFAULT, Typeface.NORMAL,
                Color.TRANSPARENT, 0, 0, 0);
        Drawable buttonBackground = props.getBackgroundDrawable();
        view.setButtonBackground(buttonBackground);

        // backspace button
        view.setBackspaceButtonTextAppearance(
                props.getBackspaceTextColor(),
                props.getBackspaceTextSize(),
                Typeface.DEFAULT, Typeface.NORMAL,
                Color.TRANSPARENT, 0, 0, 0);

        Drawable backspaceButtonBackground = props.getBackspaceBackgroundDrawable();
        view.setBackspaceButtonBackground(backspaceButtonBackground);
    }

    private static ButtonPropertyHolder get(View view) {
        Object tag = view.getTag(R.id.view_tag_props);
        if (!(tag instanceof ButtonPropertyHolder)) {
            tag = new ButtonPropertyHolder();
            view.setTag(R.id.view_tag_props, tag);
        }

        return (ButtonPropertyHolder) tag;
    }

    @Override
    public String toString() {
        return "ButtonPropertyHolder{" +
                "width=" + width +
                ", height=" + height +
                ", borderRadius=" + borderRadius +
                ", borderWidth=" + borderWidth +
                ", textSize=" + textSize +
                ", rippleColor=" + rippleColor +
                ", backgroundColor=" + backgroundColor +
                ", backgroundColorPressed=" + backgroundColorPressed +
                ", backgroundColorDisabled=" + backgroundColorDisabled +
                ", borderColor=" + borderColor +
                ", borderColorPressed=" + borderColorPressed +
                ", borderColorDisabled=" + borderColorDisabled +
                ", textColor=" + textColor +
                ", textColorPressed=" + textColorPressed +
                ", textColorDisabled=" + textColorDisabled +
                ", backspaceWidth=" + backspaceWidth +
                ", backspaceHeight=" + backspaceHeight +
                ", backspaceBorderRadius=" + backspaceBorderRadius +
                ", backspaceBorderWidth=" + backspaceBorderWidth +
                ", backspaceTextSize=" + backspaceTextSize +
                ", backspaceRippleColor=" + backspaceRippleColor +
                ", backspaceBackgroundColor=" + backspaceBackgroundColor +
                ", backspaceBackgroundColorPressed=" + backspaceBackgroundColorPressed +
                ", backspaceBackgroundColorDisabled=" + backspaceBackgroundColorDisabled +
                ", backspaceBorderColor=" + backspaceBorderColor +
                ", backspaceBorderColorPressed=" + backspaceBorderColorPressed +
                ", backspaceBorderColorDisabled=" + backspaceBorderColorDisabled +
                ", backspaceTextColor=" + backspaceTextColor +
                ", backspaceTextColorPressed=" + backspaceTextColorPressed +
                ", backspaceTextColorDisabled=" + backspaceTextColorDisabled +
                '}';
    }
}
