import { controls } from "./controls.js";
import { loadSprite } from "./loadSprite.js";
import { music } from "./music.js";
import { sfx } from "./sfx.js";
import { sound } from "./sound.js";
import { tutorial } from "./tutorial.js";

export class SoundUi {
    constructor() {
        this.layout = {
            margin: 10,
            panelWidth: 86,
            buttonBackgroundHeight: 86,
            buttonAndSliderBackgroundHeight: 253,
            buttonSize: 64,
            wheelVolumeStep: 0.1,
            sliderWidth: 32,
            sliderHeight: 148,
            sliderBottomMargin: 3,
            sliderHitPadding: 12,
            trackWidth: 8,
            handleWidth: 28,
            handleHeight: 14
        };
        this.buttonBackgroundSprite = loadSprite("assets/ui/soundUi_buttonBackground.png");
        this.buttonAndSliderBackgroundSprite = loadSprite("assets/ui/soundUi_buttonAndSliderBackground.png");
        this.soundOffSprite = loadSprite("assets/ui/sound_off.png");
        this.soundLessThanHalfSprite = loadSprite("assets/ui/sound_lessThanHalf.png");
        this.soundMoreThanHalfSprite = loadSprite("assets/ui/sound_moreThanHalf.png");
        this.soundFullSprite = loadSprite("assets/ui/sound_full.png");
        this.isOpen = false;
        this.isDragging = false;
        this.x = 0;
        this.y = 0;
    }

    reposition() {
        this.x = window.innerWidth - this.layout.margin - this.layout.panelWidth;
        this.y = window.innerHeight - this.layout.margin - this.layout.buttonBackgroundHeight;
    }

    getButtonBackgroundRect() {
        return {
            x: this.x,
            y: this.y,
            width: this.layout.panelWidth,
            height: this.layout.buttonBackgroundHeight
        };
    }

    getOpenPanelRect() {
        return {
            x: this.x,
            y: this.y + this.layout.buttonBackgroundHeight - this.layout.buttonAndSliderBackgroundHeight,
            width: this.layout.panelWidth,
            height: this.layout.buttonAndSliderBackgroundHeight
        };
    }

    getButtonRect() {
        const panelRect = this.isOpen ? this.getOpenPanelRect() : this.getButtonBackgroundRect();

        return {
            x: panelRect.x + Math.round((panelRect.width - this.layout.buttonSize) / 2),
            y: panelRect.y + panelRect.height - this.layout.buttonBackgroundHeight + Math.round((this.layout.buttonBackgroundHeight - this.layout.buttonSize) / 2),
            width: this.layout.buttonSize,
            height: this.layout.buttonSize
        };
    }

    getSliderRect() {
        const openPanelRect = this.getOpenPanelRect();
        const sliderSectionHeight = this.layout.buttonAndSliderBackgroundHeight - this.layout.buttonBackgroundHeight;

        return {
            x: openPanelRect.x + Math.round((openPanelRect.width - this.layout.sliderWidth) / 2),
            y: openPanelRect.y + sliderSectionHeight - this.layout.sliderHeight - this.layout.sliderBottomMargin,
            width: this.layout.sliderWidth,
            height: this.layout.sliderHeight
        };
    }

    getSliderHitRect() {
        const sliderRect = this.getSliderRect();

        return {
            x: sliderRect.x - this.layout.sliderHitPadding,
            y: sliderRect.y,
            width: sliderRect.width + this.layout.sliderHitPadding * 2,
            height: sliderRect.height
        };
    }

    isPointInRect(x, y, rect) {
        return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height;
    }

    isPointInside(x, y) {
        if (this.isDragging) {
            return true;
        }

        if (this.isPointInRect(x, y, this.getButtonBackgroundRect())) {
            return true;
        }

        return this.isOpen && this.isPointInRect(x, y, this.getOpenPanelRect());
    }

    getVolume() {
        return sound.getVolume();
    }

    toggleOpen() {
        this.isOpen = !this.isOpen;
        if (!this.isOpen) {
            this.isDragging = false;
        }
    }

    close() {
        this.isOpen = false;
        this.isDragging = false;
    }

    setVolumeFromMouse(mouseY) {
        const sliderRect = this.getSliderRect();
        const relativeY = (mouseY - sliderRect.y) / sliderRect.height;
        const normalizedVolume = 1 - relativeY;
        sound.setVolume(normalizedVolume);
    }

    adjustVolumeByStep(direction) {
        if (direction === 0) {
            return;
        }

        const volumeStep = this.layout.wheelVolumeStep * direction;
        sound.setVolume(this.getVolume() + volumeStep);
    }

    handleLeftClick(x, y) {
        if (this.isPointInRect(x, y, this.getButtonBackgroundRect())) {
            music.unlock();
            sfx.unlock();
            this.toggleOpen();
            tutorial.trigger("sound.open");
            return true;
        }

        if (this.isOpen && this.isPointInRect(x, y, this.getSliderHitRect())) {
            this.setVolumeFromMouse(y);
            this.isDragging = true;
            return true;
        }

        if (this.isOpen && this.isPointInRect(x, y, this.getOpenPanelRect())) {
            return true;
        }

        return false;
    }

    update() {
        if (!this.isDragging) {
            return;
        }

        if (!controls.mouse.buttons.left) {
            this.isDragging = false;
            return;
        }

        this.setVolumeFromMouse(controls.mouse.y);
    }

    handleWheel() {
        const wheelDeltaY = controls.mouse.wheel.deltaY;
        const isMouseOverSoundUi = this.isPointInside(controls.mouse.x, controls.mouse.y);

        if (!this.isOpen || !isMouseOverSoundUi || wheelDeltaY === 0) {
            return false;
        }

        this.adjustVolumeByStep(wheelDeltaY < 0 ? 1 : -1);
        return true;
    }

    getButtonSprite() {
        const currentTutorialStep = tutorial.getCurrentStep();
        if (currentTutorialStep?.trigger === "sound.open") {
            return this.soundOffSprite;
        }

        const volume = this.getVolume();

        if (volume <= 0) {
            return this.soundOffSprite;
        }

        if (volume >= 1) {
            return this.soundFullSprite;
        }

        if (volume < 0.5) {
            return this.soundLessThanHalfSprite;
        }

        return this.soundMoreThanHalfSprite;
    }

    drawButton(ctx) {
        const sprite = this.getButtonSprite();
        const buttonRect = this.getButtonRect();

        if (!sprite || !sprite.complete) {
            return;
        }

        ctx.drawImage(sprite, buttonRect.x, buttonRect.y, buttonRect.width, buttonRect.height);
    }

    drawBackground(ctx) {
        const sprite = this.isOpen ? this.buttonAndSliderBackgroundSprite : this.buttonBackgroundSprite;
        const rect = this.isOpen ? this.getOpenPanelRect() : this.getButtonBackgroundRect();

        if (!sprite || !sprite.complete) {
            return;
        }

        ctx.drawImage(sprite, rect.x, rect.y, rect.width, rect.height);
    }

    drawSlider(ctx) {
        if (!this.isOpen) {
            return;
        }

        const sliderRect = this.getSliderRect();
        const trackX = sliderRect.x + Math.round((sliderRect.width - this.layout.trackWidth) / 2);
        const handleTravel = sliderRect.height - this.layout.handleHeight;
        const handleY = sliderRect.y + Math.round((1 - this.getVolume()) * handleTravel);

        ctx.save();

        ctx.fillStyle = "rgba(48, 39, 34, 0.8)";
        ctx.fillRect(trackX, sliderRect.y, this.layout.trackWidth, sliderRect.height);

        ctx.fillStyle = "rgba(189, 182, 160, 0.95)";
        ctx.fillRect(trackX, handleY + Math.floor(this.layout.handleHeight / 2), this.layout.trackWidth, sliderRect.y + sliderRect.height - handleY - Math.floor(this.layout.handleHeight / 2));

        ctx.fillStyle = "#d7d2bf";
        ctx.fillRect(sliderRect.x + Math.round((sliderRect.width - this.layout.handleWidth) / 2), handleY, this.layout.handleWidth, this.layout.handleHeight);

        ctx.strokeStyle = "#3F2517";
        ctx.lineWidth = 2;
        ctx.strokeRect(
            sliderRect.x + Math.round((sliderRect.width - this.layout.handleWidth) / 2) + 1,
            handleY + 1,
            this.layout.handleWidth - 2,
            this.layout.handleHeight - 2
        );

        ctx.restore();
    }

    draw(ctx) {
        this.reposition();
        this.drawBackground(ctx);
        this.drawSlider(ctx);
        this.drawButton(ctx);
    }
}

export const soundUi = new SoundUi();