import { Renderer } from 'pixi.js';
import { Pane } from 'tweakpane';
import Viewport from './Viewport';

import type { ViewportOptions } from '../types';

/**
 * DebugViewport is a development extension of the standard Viewport.
 *
 * It integrates a Tweakpane panel to visualize and test resize behavior,
 * and allows toggling the panel with the "R" key.
 */
export default class DebugViewport extends Viewport
{
    private pane: Pane;
    private readonly _params: { skin: number };
    private readonly handleKeydown: (event: KeyboardEvent) => void;

    constructor(options: ViewportOptions, renderer: Renderer)
    {
        super(options, renderer);

        const container = (document.body.querySelector('.content') as HTMLElement) ?? document.body;

        this.pane = new Pane({
            title: 'RESIZE',
            container
        });

        // Apply a high z-index safely
        (this.pane.element as HTMLElement).style.zIndex = '1000';

        this._params = {
            skin: 0
        };
        // @ts-expect-error: method addBinding exists in Tweakpane 4 but missing in types
        this.pane.addBinding(this._params, 'skin');

        this.handleKeydown = this.onKeyDown.bind(this);
        document.addEventListener('keydown', this.handleKeydown);
        // @ts-expect-error: property hidden exists in Tweakpane 4 but missing in types
        this.pane.hidden = true;
    }

    /** Overrides the resize method to update debug panel values after performing the standard Viewport resize behavior. */
    override resize(): void
    {
        super.resize();
        this._params.skin = this.getSkin();
        // @ts-expect-error: method refresh exists in Tweakpane 4 but missing in types
        this.pane.refresh();
    }

    /**
     * Returns the current skin value for resizing a Spine scene using a grid system.
     * The value is based on cropWidthRatio and aligned to the nearest multiple of 10.
     * @returns A number between 20 and 100 (in steps of 10), representing the current skin.
     */
    private getSkin(): number
    {
        const raw = Math.floor(this.cropWidthRatio * 10) * 10;

        return Math.min(100, Math.max(20, raw));
    }

    /**
     * Handles toggling the debug pane on key press ('R').
     * @param event
     */
    private onKeyDown(event: KeyboardEvent): void
    {
        if (event.key === 'r' || event.key === 'R')
        {
            // @ts-expect-error: property hidden exists in Tweakpane 4 but missing in types
            this.pane.hidden = !this.pane.hidden;
        }
    }

    /** Cleans up listeners and UI elements. */
    override dispose(): void
    {
        document.removeEventListener('keydown', this.handleKeydown);
        this.pane.dispose();
        super.dispose();
    }
}
