/*
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/stores/entitlementsStore.js
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
*/
// ─────────────────────────────────────────────────────────────────────────
// entitlementsStore — features que o PLANO PERMITE (read-only, derivado).
//
// Separação V#41 (Opção B2):
//   entitlementsStore.has(key)       = "o plano permite essa feature?"
//   tenantFeaturesStore.isEnabled(k) = "essa feature está ATIVA agora?"
//                                       (combina plano + override)
//
// Source: views v_tenant_entitlements (plano da clínica) e v_user_entitlements
// (assinatura pessoal — solo therapist/supervisor). has() sem scope = união.
// ─────────────────────────────────────────────────────────────────────────

import { defineStore } from 'pinia';
import { supabase } from '@/lib/supabase/client';
import { logError } from '@/support/supportLogger';

function normalizeKey(k) {
    return String(k || '').trim();
}

function uniqKeys(rows, field) {
    const list = [];
    const seen = new Set();
    for (const r of rows || []) {
        const key = normalizeKey(r?.[field]);
        if (!key) continue;
        if (seen.has(key)) continue;
        seen.add(key);
        list.push(key);
    }
    return list;
}

export const useEntitlementsStore = defineStore('entitlements', {
    state: () => ({
        // =========================
        // Tenant entitlements (B)
        // =========================
        tenantLoading: false,
        loadedForTenant: null,
        tenantFeatures: [],
        tenantRaw: [],
        tenantError: null,
        tenantLoadedAt: null,

        // =========================
        // User entitlements (A)
        // =========================
        userLoading: false,
        loadedForUser: null,
        userFeatures: [],
        userRaw: [],
        userError: null,
        userLoadedAt: null
    }),

    getters: {
        /**
         * ✅ Sem scope: união de tenant + user entitlements.
         * Um terapeuta com plano pessoal (therapist_pro) tem features em userFeatures,
         * não em tenantFeatures — ambos devem ser verificados.
         */
        has:
            (state) =>
            (featureKey, scope = null) => {
                const key = normalizeKey(featureKey);
                if (!key) return false;

                if (scope === 'tenant') return state.tenantFeatures.includes(key);
                if (scope === 'user') return state.userFeatures.includes(key);

                // sem scope: true se qualquer uma das origens tiver a feature
                return state.tenantFeatures.includes(key) || state.userFeatures.includes(key);
            },

        can:
            (state) =>
            (featureKey, scope = null) => {
                const key = normalizeKey(featureKey);
                if (!key) return false;

                if (scope === 'tenant') return state.tenantFeatures.includes(key);
                if (scope === 'user') return state.userFeatures.includes(key);

                return state.tenantFeatures.includes(key) || state.userFeatures.includes(key);
            }
    },

    actions: {
        // =========================
        // Compat: fetch() continua existindo
        // =========================
        async fetch(tenantId, opts = {}) {
            return this.loadForTenant(tenantId, opts);
        },

        clear() {
            return this.invalidate();
        },

        // =========================
        // Tenant (clinic) — view v_tenant_entitlements
        // =========================
        async loadForTenant(tenantId, { force = false, maxAgeMs = 0 } = {}) {
            if (!tenantId) {
                this.invalidateTenant();
                return;
            }

            const same = this.loadedForTenant === tenantId;
            const hasLoadedAt = typeof this.tenantLoadedAt === 'number';
            const isFresh = same && hasLoadedAt && maxAgeMs > 0 && Date.now() - this.tenantLoadedAt < maxAgeMs;

            if (!force && same && (maxAgeMs === 0 || isFresh)) return;

            this.tenantLoading = true;
            this.tenantError = null;

            try {
                const { data, error } = await supabase.from('v_tenant_entitlements').select('feature_key').eq('tenant_id', tenantId);

                if (error) throw error;

                const rows = data ?? [];
                this.tenantRaw = rows;
                this.tenantFeatures = uniqKeys(rows, 'feature_key');

                this.loadedForTenant = tenantId;
                this.tenantLoadedAt = Date.now();
            } catch (e) {
                // V#42: NÃO marcar como carregado em caso de erro — força próximo
                // request a tentar de novo em vez de mascarar com array vazio.
                this.tenantError = e;
                this.tenantRaw = [];
                this.tenantFeatures = [];
                logError('entitlementsStore.loadForTenant', `tenantId=${tenantId}`, e);
            } finally {
                this.tenantLoading = false;
            }
        },

        // =========================
        // User (therapist personal) — view v_user_entitlements
        // =========================
        async loadForUser(userId, { force = false, maxAgeMs = 0 } = {}) {
            if (!userId) {
                this.invalidateUser();
                return;
            }

            const same = this.loadedForUser === userId;
            const hasLoadedAt = typeof this.userLoadedAt === 'number';
            const isFresh = same && hasLoadedAt && maxAgeMs > 0 && Date.now() - this.userLoadedAt < maxAgeMs;

            if (!force && same && (maxAgeMs === 0 || isFresh)) return;

            this.userLoading = true;
            this.userError = null;

            try {
                const { data, error } = await supabase.from('v_user_entitlements').select('feature_key').eq('user_id', userId);

                if (error) throw error;

                const rows = data ?? [];
                this.userRaw = rows;
                this.userFeatures = uniqKeys(rows, 'feature_key');

                this.loadedForUser = userId;
                this.userLoadedAt = Date.now();
            } catch (e) {
                // V#42: mesmo tratamento de loadForTenant — não marca como carregado.
                this.userError = e;
                this.userRaw = [];
                this.userFeatures = [];
                logError('entitlementsStore.loadForUser', `userId=${userId}`, e);
            } finally {
                this.userLoading = false;
            }
        },

        // =========================
        // Invalidate granular
        // =========================
        invalidateTenant() {
            this.tenantLoading = false;
            this.loadedForTenant = null;
            this.tenantFeatures = [];
            this.tenantRaw = [];
            this.tenantError = null;
            this.tenantLoadedAt = null;
        },

        invalidateUser() {
            this.userLoading = false;
            this.loadedForUser = null;
            this.userFeatures = [];
            this.userRaw = [];
            this.userError = null;
            this.userLoadedAt = null;
        },

        // =========================
        // Invalidate geral (compat)
        // =========================
        invalidate() {
            this.invalidateTenant();
            this.invalidateUser();
        }
    }
});
