/**
 * BindableColorWidget — a color picker that can optionally bind to a color value source.
 *
 * Renders a color input with a small toggle button. When toggled to
 * "bound" mode, shows an EntitySelect color value source picker.
 * Emits a BindableColor value: plain [R,G,B] (static) or {color, source_id} (bound).
 */

import type { BindableColor } from '../types.ts';
import { bindableColor, bindableColorSourceId } from '../types.ts';
import { EntitySelect } from './entity-palette.ts';
import { getValueSourceIcon } from './icons.ts';
import { t } from './i18n.ts';

export interface BindableColorOpts {
    container: HTMLElement;
    default: number[];
    /** Only show color value sources (return_type="color") */
    valueSources: () => Array<{ id: string; name: string; source_type: string; return_type?: string }>;
    onChange?: (value: BindableColor) => void;
    idPrefix?: string;
    noneLabel?: string;
}

let _widgetCounter = 0;

export class BindableColorWidget {
    private _container: HTMLElement;
    private _opts: BindableColorOpts;
    private _id: string;
    private _bound: boolean = false;
    private _staticColor: number[];
    private _sourceId: string = '';
    private _entitySelect: EntitySelect | null = null;

    private _colorRow!: HTMLElement;
    private _vsRow!: HTMLElement;
    private _colorInput!: HTMLInputElement;
    private _toggleBtn!: HTMLButtonElement;
    private _select!: HTMLSelectElement;

    constructor(opts: BindableColorOpts) {
        this._opts = opts;
        this._container = opts.container;
        this._staticColor = [...opts.default];
        this._id = opts.idPrefix || `bcw-${++_widgetCounter}`;
        this._render();
    }

    private _rgbToHex(rgb: number[]): string {
        return '#' + rgb.map(c => Math.max(0, Math.min(255, c)).toString(16).padStart(2, '0')).join('');
    }

    private _hexToRgb(hex: string): number[] {
        const m = hex.replace('#', '').match(/.{2}/g);
        return m ? m.map(h => parseInt(h, 16)) : [255, 255, 255];
    }

    private _render(): void {
        const id = this._id;
        const hex = this._rgbToHex(this._staticColor);

        const toggleSvg = `<svg class="icon icon-xs" viewBox="0 0 24 24"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/></svg>`;

        const colorHtml = `<div class="bindable-slider-row" id="${id}-color-row">
            <input type="color" id="${id}-color" value="${hex}">
            <button type="button" class="bindable-toggle" id="${id}-toggle" title="${t('bindable.toggle')}">${toggleSvg}</button>
        </div>`;

        const vsHtml = `<div class="bindable-vs-row" id="${id}-vs-row" style="display:none">
            <select id="${id}-select"></select>
            <button type="button" class="bindable-toggle bindable-toggle--active" id="${id}-untoggle" title="${t('bindable.toggle')}">${toggleSvg}</button>
        </div>`;

        this._container.innerHTML = colorHtml + vsHtml;

        this._colorRow = document.getElementById(`${id}-color-row`)!;
        this._vsRow = document.getElementById(`${id}-vs-row`)!;
        this._colorInput = document.getElementById(`${id}-color`) as HTMLInputElement;
        this._select = document.getElementById(`${id}-select`) as HTMLSelectElement;
        this._toggleBtn = document.getElementById(`${id}-toggle`) as HTMLButtonElement;

        this._colorInput.addEventListener('input', () => {
            this._staticColor = this._hexToRgb(this._colorInput.value);
            this._fireChange();
        });

        this._toggleBtn.addEventListener('click', () => this._setMode(true));
        document.getElementById(`${id}-untoggle`)!.addEventListener('click', () => this._setMode(false));
    }

    private _setMode(bound: boolean): void {
        this._bound = bound;
        this._colorRow.style.display = bound ? 'none' : '';
        this._vsRow.style.display = bound ? '' : 'none';
        if (bound) {
            this._populateVsSelect();
        } else {
            this._sourceId = '';
            if (this._entitySelect) { this._entitySelect.destroy(); this._entitySelect = null; }
        }
        this._fireChange();
    }

    private _populateVsSelect(): void {
        // Filter to only color value sources
        const sources = this._opts.valueSources().filter(vs => vs.return_type === 'color');

        this._select.innerHTML = `<option value="">${this._opts.noneLabel || t('bindable.none')}</option>` +
            sources.map(vs =>
                `<option value="${vs.id}"${vs.id === this._sourceId ? ' selected' : ''}>${vs.name}</option>`
            ).join('');

        if (this._entitySelect) this._entitySelect.destroy();
        this._entitySelect = new EntitySelect({
            target: this._select,
            getItems: () => sources.map(vs => ({
                value: vs.id,
                label: vs.name,
                icon: getValueSourceIcon(vs.source_type),
                desc: vs.source_type,
            })),
            placeholder: t('palette.search'),
            allowNone: true,
            noneLabel: t('bindable.none'),
            onChange: (value: string) => {
                this._sourceId = value;
                this._fireChange();
            },
        });
    }

    private _fireChange(): void {
        if (this._opts.onChange) {
            this._opts.onChange(this.getValue());
        }
    }

    getValue(): BindableColor {
        if (this._bound && this._sourceId) {
            return { color: [...this._staticColor], source_id: this._sourceId };
        }
        return [...this._staticColor];
    }

    setValue(bc: BindableColor | undefined): void {
        this._staticColor = bindableColor(bc, this._opts.default);
        this._sourceId = bindableColorSourceId(bc);
        this._bound = !!this._sourceId;

        this._colorInput.value = this._rgbToHex(this._staticColor);
        this._colorRow.style.display = this._bound ? 'none' : '';
        this._vsRow.style.display = this._bound ? '' : 'none';

        if (this._bound) {
            this._populateVsSelect();
        }
    }

    refresh(): void {
        if (this._bound) this._populateVsSelect();
    }

    destroy(): void {
        if (this._entitySelect) { this._entitySelect.destroy(); this._entitySelect = null; }
        this._container.innerHTML = '';
    }
}
