package cz.jzitnik.game.ui;

import org.jline.terminal.MouseEvent;
import org.jline.terminal.Terminal;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.sprites.ui.Font.*;
import cz.jzitnik.tui.ScreenRenderer;
import lombok.extern.slf4j.Slf4j;

/**
 * Represents the options menu where the user can configure settings
 * such as sound volume using a slider UI.
 */
@Slf4j
public class Options {
    private Game game;
    private int top;
    private int sliderWidth;
    private int sliderLeftpad;

    /**
     * Creates an Options menu for the given game instance.
     *
     * @param game the game instance providing configuration and resources
     */
    public Options(Game game) {
        this.game = game;
    }


    /**
     * Renders the options menu UI including the heading, labels,
     * and the volume slider.
     *
     * @param buffer   the string builder to append the rendered UI
     * @param terminal the terminal context for size and rendering info
     */
    public void render(StringBuilder buffer, Terminal terminal) {
        var buf = new StringBuilder();
        var font = game.getGameStates().dependencies.font;
        var config = game.getConfiguration();

        var mainText = font.line(terminal, "Options", Align.CENTER, Size.LARGE);
        buf.append(mainText.getData());

        buf.append("\n".repeat(15));

        var sounds = font.line(terminal, "Sounds", Align.CENTER, Size.MEDIUM);
        buf.append(sounds.getData());

        buf.append("\n".repeat(10));

        top = mainText.getHeight() + 15 + sounds.getHeight() + 10;

        renderSlider(buf, terminal, config.getSoundVolume());

        buffer.append(buf);
    }

    /**
     * Renders the slider bar indicating the current volume percentage.
     *
     * @param buffer     the string builder to append the slider UI
     * @param terminal   the terminal context for width and rendering
     * @param percentage the current volume percentage to display
     */
    private void renderSlider(StringBuilder buffer, Terminal terminal, int percentage) {
        var defaultColor = "\033[48;2;116;115;113m";
        var fullColor = "\033[48;2;70;70;70m";
        int width = Math.min(550, (int) (terminal.getWidth() * (3.0 / 4)));
        int leftPad = (terminal.getWidth() - width) / 2;
        sliderLeftpad= leftPad;
        sliderWidth = width;

        for (int i = 0; i < 8; i++) {
            buffer.append(" ".repeat(leftPad));

            for (int j = 0; j < width; j++) {
                if (((double) j / width) * 100 <= percentage) {
                    buffer.append(fullColor).append(" ");
                } else {
                    buffer.append(defaultColor).append(" ");
                }
            }

            buffer.append("\033[0m").append("\n");
        }
    }

    /**
     * Handles mouse input events to update the sound volume based on
     * slider interaction.
     *
     * @param mouseEvent     the mouse event containing position and type
     * @param terminal       the terminal context for coordinate mapping
     * @param screenRenderer the renderer to update the screen after changes
     */
    public void handleMouse(MouseEvent mouseEvent, Terminal terminal, ScreenRenderer screenRenderer) {
        int x = mouseEvent.getX();
        int y = mouseEvent.getY() - top;

        if (x > sliderLeftpad && x <= sliderLeftpad + sliderWidth) {
            if (y > 0 && y <= 8) {
                if (mouseEvent.getType() == MouseEvent.Type.Pressed || mouseEvent.getType() == MouseEvent.Type.Dragged) {
                    int sliderX = x - sliderLeftpad;
                    int percentage = (int) Math.round((((double) sliderX / sliderWidth) * 100));

                    game.getConfiguration().setSoundVolume(percentage);
                    log.info("Sound volume was changed to: {}% ", percentage);

                    screenRenderer.render(game);
                }
            }
        }
    }
}
