export class Controller {

    constructor(form) {
        this.root = form;
        this.output = form.querySelector('.output');
        form.nchanctl = this;

        this.onopen = null;
        this.onclose = null;
        this.onmessage = null;
        this.onrequest = null;

        this.errors = [];

        let btn;

        this.connectBtn = this.root.querySelector('input[name=connect]');
        this.connectBtn.addEventListener('click', evt => {
            let action;
            if (evt.target.value === 'Connect') {
                evt.target.value = 'Close';
                action = this.onopen;
            } else {
                evt.target.value = 'Connect';
                action = this.onclose;
            }
            if (typeof action === 'function') Promise.resolve()
                .then(action)
                .catch(console.error.bind(console,'Action has failed:'));
        });
        this.root.querySelector('input[name=clear]').addEventListener('click', evt => {
            this.output.textContent = '';
        });

        btn = this.root.querySelector('input[name=message]');
        if (btn) btn.addEventListener('click', evt => {
            if (typeof this.onmessage === 'function')
                this.onmessage(this.name, this.payload, this.channels)
        });

        btn = this.root.querySelector('input[name=request]');
        if (btn) btn.addEventListener('click', evt => {
            if (typeof this.onrequest === 'function')
                this.onrequest(this.name, this.payload, this.channels)
        });

        btn = this.root.querySelector('input[name=post]');
        if (btn) btn.addEventListener('click', evt => {
            fetch('./example/post.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    'name': this.name,
                    'payload': this.payload,
                    'channels': this.channels
                })
            }).then(async response => {
                if (response.ok) {
                    return { type: 'message', payload: await response.text() };
                } else {
                    return { type: 'error', payload: `HTTP ${response.status}: ${response.statusText}` };
                }
            }).then(data => {
                console.info('Post result:', data);
                this.post({ name: 'post result', channel: 'ctl', ...data });
            });
        });
    }

    set status(value) {
        this.root.querySelector('.status-content').textContent = value;
        this.connectBtn.value = value.startsWith('clo') ? 'Connect' : 'Close';
    }

    post({ timestamp, name, type, channel, payload } = {}) {
        const cnt = document.createElement('div');
        cnt.className = 'message';
        const header = document.createElement('div');
        header.className = type || 'message';
        header.textContent = '[' + (timestamp ? new Date(timestamp*1000) : new Date()).toLocaleTimeString() + `] ${channel || 'internal'} : ${name}`;
        cnt.append(header);
        if (typeof payload !== 'undefined') {
            try {
                if (typeof payload === 'string') payload = JSON.parse(payload);
                cnt.append(JSON.stringify(payload, null, 4));
            } catch(err) {
                cnt.append(payload);
            }
        }
        this.output.prepend(cnt);
    }

    handleError(error, name='error') {
        let payload = '';
        if (error instanceof Error || error instanceof DOMException) {
            payload = `[${error.name}] ${error.message}`;
        }
        this.post({ type: 'error', name, payload })
        this.errors.push(error);
        console.error(error);
    }

    get type() {
        const checked = this.root.querySelector('input[type=radio]:checked');
        return checked ? checked.value : 'message';
    }

    get channels() {
        const checked = [...this.root.querySelectorAll('input[type=checkbox]:checked')].map(x => x.name);
        return checked.length ? checked : null;
    }

    get payload() {
        const value = this.root.querySelector('textarea').value;
        try {
            return JSON.parse(value);
        } catch(err) {
            return value;
        }
    }

    get name() {
        return this.root.querySelector('input[name=name]').value;
    }
}
