/**
 * Angular wrapper for Bryntum Theme combo
 */
import { Component, ElementRef, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { BrowserHelper, Combo, DomHelper, Store, StoreConfig } from '@bryntum/calendar';
import { initThemeInShadowRoots, registerShadowRoot, unregisterShadowRoot } from './shadowdom.helper';

const defaultThemes: Record<string, string> = {
    'material3-light'     : 'Material3 Light',
    'material3-dark'      : 'Material3 Dark',
    'stockholm-light'     : 'Stockholm Light',
    'stockholm-dark'      : 'Stockholm Dark',
    'svalbard-light'      : 'Svalbard Light',
    'svalbard-dark'       : 'Svalbard Dark',
    'visby-light'         : 'Visby Light',
    'visby-dark'          : 'Visby Dark',
    'fluent2-light'       : 'Fluent2 Light',
    'fluent2-dark'        : 'Fluent2 Dark',
    'high-contrast-light' : 'High Contrast Light',
    'high-contrast-dark'  : 'High Contrast Dark'
};

const syncedProps = ['store', 'label', 'width'] as const;

export type BryntumThemeComboProps = {
    store?: Store | StoreConfig | object;
    label?: string;
    width?: string | number;
};

@Component({
    selector : 'bryntum-theme-combo',
    template : ''
})
export class BryntumThemeComboComponent implements OnInit, OnChanges, OnDestroy {

    private elementRef: ElementRef;
    private combo!: Combo;

    @Input() store?: Store | StoreConfig | object;
    @Input() label?: string;
    @Input() width?: string | number;

    constructor(element: ElementRef) {
        this.elementRef = element;
    }

    /**
     * Initializes the component and creates the Bryntum Combo widget
     */
    ngOnInit(): void {
        const shadowRoot = this.elementRef.nativeElement.getRootNode();
        if (shadowRoot instanceof ShadowRoot) {
            registerShadowRoot(shadowRoot);
        }

        this.combo = new Combo({
            appendTo      : this.elementRef.nativeElement,
            ...(this.store ? { store : this.store } : { items : defaultThemes }),
            label         : this.label ?? 'Theme',
            width         : this.width ?? '16em',
            value         : 'material3-light',
            editable      : false,
            labelPosition : 'before',
            ref           : 'themeCombo',
            listeners     : {
                change({ value }) {
                    DomHelper.setTheme(value).then(context => {
                        if (context) {
                            // Remove all b-theme-* classes — don't rely on context.prev which may
                            // be stale (CSS vars unreadable in Angular ViewEncapsulation.ShadowDom)
                            Array.from(document.body.classList)
                                .filter(cls => cls.startsWith('b-theme-'))
                                .forEach(cls => document.body.classList.remove(cls));
                            document.body.classList.add(`b-theme-${context.theme}`);
                        }
                    });
                }
            }
        });

        // Apply theme from URL search param (?theme=xxx), detect from loaded CSS, or read from link href
        const
            themeLink     = document.querySelector<HTMLLinkElement>('link[data-bryntum-theme]'),
            themeFromHref = themeLink ? new URL(themeLink.href).pathname.split('/').pop()?.replace('.css', '') : '',
            theme         = BrowserHelper.searchParam('theme') || DomHelper.getThemeInfo()?.filename || themeFromHref;

        if (theme) {
            this.combo.value = theme;
        }

        console.log(`Set: .b-theme-${this.combo.value as string}`);
        // Always set the initial body class — even when theme detection falls back to the
        // combo's default value (CSS vars may be unreadable in shadow DOM contexts)
        document.body.classList.add(`b-theme-${this.combo.value as string}`);

        initThemeInShadowRoots();
    }

    /**
     * Responds to Input property changes and updates the Combo widget accordingly
     */
    ngOnChanges(changes: SimpleChanges): void {
        const { combo } = this;
        if (!combo) {
            return;
        }
        for (const prop of syncedProps) {
            if (prop in changes) {
                (combo as any)[prop] = changes[prop].currentValue;
            }
        }
    }

    /**
     * Destroys the component and the underlying Combo widget
     */
    ngOnDestroy(): void {
        const shadowRoot = this.elementRef.nativeElement.getRootNode();
        if (shadowRoot instanceof ShadowRoot) {
            unregisterShadowRoot(shadowRoot);
        }

        if (this.combo) {
            this.combo.destroy();
        }
    }
}
