export default class ApiClient {

    constructor({ config = {}, store, eventBus } = {}) {
        this.store    = store;
        this.eventBus = eventBus;
        this.apiFetch = window.wp?.apiFetch;

        const base  = config.apiUrl || '/wp-json/acc/v1';
        this.baseUrl = base.replace(/\/+$/, '');
    }

    getToken() {
        return (
            this.store?.get('session')?.token ||
            sessionStorage.getItem('acc_token') ||
            null
        );
    }

    buildHeaders(extra = {}) {
        const headers = {
            'Content-Type': 'application/json',
            'Accept':       'application/json',
            ...extra,
        };

        const token = this.getToken();
        if (token) {
            headers['Authorization'] = `Bearer ${token}`;
        }

        return headers;
    }

    async request(method, endpoint, data = null, options = {}) {

        const cleanEndpoint = String(endpoint || '').replace(/^\/+/, '');
        let url = `${this.baseUrl}/${cleanEndpoint}`;
        url = url.replace(/([^:]\/)\/+/g, '$1');

        if (options.query && typeof options.query === 'object') {
            const params = new URLSearchParams();
            Object.entries(options.query).forEach(([key, value]) => {
                if (value !== undefined && value !== null && value !== '') {
                    params.append(key, value);
                }
            });
            const qs = params.toString();
            if (qs) {
                url += (url.includes('?') ? '&' : '?') + qs;
            }
        }

        const requestOptions = {
            method,
            headers: this.buildHeaders(options.headers || {}),
        };

        if (data && method !== 'GET' && method !== 'HEAD') {
            requestOptions.body = JSON.stringify(data);
        }

        const response = await fetch(url, requestOptions);

        let json = null;
        try {
            json = await response.json();
        } catch (e) {
            json = null;
        }

        if (!response.ok) {
            if (response.status === 401) {
                this.handleUnauthorized();
            }
            throw new Error(json?.message || `HTTP ${response.status}`);
        }

        return json;
    }

    handleUnauthorized() {
        sessionStorage.removeItem('acc_token');

        this.store?.set('auth', {
            user:     null,
            loggedIn: false,
        });

        this.eventBus?.emit('auth:unauthorized');
    }

    get(endpoint, params = {}, options = {}) {
        return this.request('GET', endpoint, null, { ...options, query: params });
    }

    post(endpoint, data = {}, options = {}) {
        return this.request('POST', endpoint, data, options);
    }

    put(endpoint, data = {}, options = {}) {
        return this.request('PUT', endpoint, data, options);
    }

    delete(endpoint, options = {}) {
        return this.request('DELETE', endpoint, null, options);
    }
}
