/**
 * AclService.js — سرویس مرکزی دسترسی‌های کاربر فعلی
 *
 * استفاده:
 *   import acl from '../core/AclService.js';
 *
 *   await acl.load(api);              // یک‌بار در bootstrap
 *   if (acl.can('gis.parcels.edit')) { ... }
 *   acl.menus                          // لیست منوهای مجاز
 *   acl.roles                          // نقش‌های کاربر
 *   acl.refresh()                      // بازخوانی از سرور
 */

class AclService {

    constructor() {
        this._loaded      = false;
        this._loadPromise = null;
        this._api         = null;

        this.userId      = null;
        this.roles       = [];           // [{ slug, name, scope_type, scope_id }]
        this.permissions = new Map();    // key → Set of scopes
        this.menus       = [];           // [{ menu_key, title, route, ... }]
        this.scopes      = {};           // { warehouse: { unrestricted, ids }, ... }

        this._listeners = new Set();
    }

    /* یک‌بار لود کن (با cache) */
    async load(api) {
        if (this._loaded) return this;
        if (this._loadPromise) return this._loadPromise;

        this._api = api;
        this._loadPromise = this._fetchMe();
        await this._loadPromise;
        this._loadPromise = null;
        return this;
    }

    /* بازخوانی اجباری از سرور */
    async refresh() {
        this._loaded = false;
        this.permissions.clear();
        this.roles = [];
        this.menus = [];
        this.scopes = {};
        return this.load(this._api);
    }

    async _fetchMe() {
        try {
            const res = await this._api.get('/acl/me');

            this.userId = res?.user_id ?? null;
            this.roles  = res?.roles   ?? [];
            this.menus  = res?.menus   ?? [];
            this.scopes = res?.scopes  ?? {};

            this.permissions.clear();
            for (const p of (res?.permissions ?? [])) {
                if (!this.permissions.has(p.key)) {
                    this.permissions.set(p.key, new Set());
                }
                const scope = p.scope_type === 'global' || !p.scope_id
                    ? '*'
                    : `${p.scope_type}:${p.scope_id}`;
                this.permissions.get(p.key).add(scope);
            }

            this._loaded = true;
            this._notify();
        } catch (e) {
            console.warn('AclService.load failed', e);
            this._loaded = true; // برای جلوگیری از retry بی‌نهایت
        }
    }

    /**
     * بررسی مجوز
     * @param {string} key - مثلاً 'gis.parcels.edit'
     * @param {string} [scopeType] - 'project' | 'warehouse' | 'district' | ...
     * @param {number} [scopeId]
     * @returns {boolean}
     */
    can(key, scopeType = null, scopeId = null) {
        if (!this._loaded) return false;

        const scopes = this.permissions.get(key);
        if (!scopes) return false;

        // مجوز سراسری همیشه کار می‌کند
        if (scopes.has('*')) return true;

        if (scopeType && scopeId !== null) {
            return scopes.has(`${scopeType}:${scopeId}`);
        }

        // اگر scope خاص خواسته نشد، فقط اگر سراسری دارد true
        return false;
    }

    /** alias کوتاه */
    cannot(key, scopeType = null, scopeId = null) {
        return !this.can(key, scopeType, scopeId);
    }

    /** آیا نقش خاصی دارد؟ */
    hasRole(slug) {
        return this.roles.some(r => r.slug === slug);
    }

    /** آیا کاربر super_admin است؟ */
    isSuperAdmin() {
        return this.hasRole('super_admin');
    }

    /**
     * فیلتر آرایه‌ای از تب‌ها بر اساس مجوزها
     * هر آیتم باید field 'requiredPermission' یا 'permission' داشته باشد
     */
    filterByPermission(items, permField = 'requiredPermission') {
        return items.filter(item => {
            const req = item[permField] ?? item.permission ?? null;
            return !req || this.can(req);
        });
    }

    /** فیلتر لیست اشیاء scope (مثلاً انبارها) */
    filterScopeList(items, scopeType = 'warehouse', idField = 'id') {
        const sc = this.scopes?.[scopeType];
        if (!sc || sc.unrestricted) return items;
        const allowed = new Set((sc.ids ?? []).map(Number));
        return (items ?? []).filter(it => allowed.has(+it[idField]));
    }

    /** آیا دسترسی سراسری به scope دارد؟ */
    hasUnrestrictedScope(scopeType = 'warehouse') {
        return !!this.scopes?.[scopeType]?.unrestricted;
    }

    /** subscribe برای reactive UI */
    onUpdate(callback) {
        this._listeners.add(callback);
        return () => this._listeners.delete(callback);
    }

    _notify() {
        this._listeners.forEach(cb => {
            try { cb(this); } catch (e) { console.warn('acl listener', e); }
        });
    }
}

/* Singleton */
const acl = new AclService();

/* in browser, expose for debugging */
if (typeof window !== 'undefined') {
    window.acl = acl;
}

export default acl;
