/*
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/stores/tenantFeaturesStore.js
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
*/

// ─────────────────────────────────────────────────────────────────────────
// tenantFeaturesStore — overrides por tenant ("o que está ATIVO agora?")
//
// Funciona em conjunto com entitlementsStore ("o que o plano PERMITE?").
// V#34/V#41 — Opção B2:
//   feature ATIVA quando:
//     plano permite AND nenhum override negativo, OU
//     override positivo (exceção comercial liberada por saas_admin via RPC)
//
// Toda escrita passa pela RPC set_tenant_feature_exception (autorização +
// log + bypass controlado do trigger guard).
// ─────────────────────────────────────────────────────────────────────────

import { defineStore } from 'pinia';
import { computed, ref } from 'vue';
import { supabase } from '@/lib/supabase/client';
import { useEntitlementsStore } from '@/stores/entitlementsStore';

// V#18 — TTL configurável (default 5min). Força refetch se cache for mais
// velho que TTL. Antes lastFetchedAt era registrado mas nunca verificado.
const DEFAULT_TTL_MS = 5 * 60 * 1000;

export const useTenantFeaturesStore = defineStore('tenantFeatures', () => {
    const loading = ref(false);
    const lastError = ref(null);
    const lastFetchedAt = ref(null);

    // Cache por tenant: { [tenantId]: { [feature_key]: boolean } }
    const featuresByTenant = ref({});

    // V#18 — timestamps por tenant pra TTL granular
    const fetchedAtByTenant = ref({});

    // Marca o último tenant buscado (útil pra debug)
    const loadedForTenantId = ref(null);

    function getTenantMap(tenantId) {
        if (!tenantId) return {};
        return featuresByTenant.value?.[tenantId] || {};
    }

    /**
     * isEnabled — feature está ATIVA para o tenant?
     *
     * Combina plano (entitlementsStore) + override (tenant_features):
     *  - override negativo (false)  → INATIVO sempre
     *  - override positivo (true)   → ATIVO sempre (exceção comercial)
     *  - sem override              → segue plano
     *
     * Pré-condição: entitlementsStore deve estar carregado para o mesmo
     * tenant (loadForTenant) ou para o user (loadForUser, fallback p/ solo
     * therapist). Se não estiver, retorna false (fail-safe).
     */
    function isEnabled(key, tenantId = null) {
        const tid = tenantId || loadedForTenantId.value;
        if (!tid || !key) return false;

        const map = getTenantMap(tid);

        // Override explícito tem precedência
        if (key in map) {
            return !!map[key];
        }

        // Sem override → consulta plano
        const ent = useEntitlementsStore();

        // Tenant entitlements têm prioridade quando carregado para esse tenant
        if (ent.loadedForTenant === tid && Array.isArray(ent.tenantFeatures) && ent.tenantFeatures.includes(key)) {
            return true;
        }

        // Fallback: assinatura pessoal (solo therapist)
        if (Array.isArray(ent.userFeatures) && ent.userFeatures.includes(key)) {
            return true;
        }

        return false;
    }

    function invalidate(tenantId = null) {
        lastError.value = null;
        if (!tenantId) {
            loadedForTenantId.value = null;
            featuresByTenant.value = {};
            fetchedAtByTenant.value = {};
            return;
        }
        // invalida apenas um tenant
        const copy = { ...featuresByTenant.value };
        delete copy[tenantId];
        featuresByTenant.value = copy;
        const tCopy = { ...fetchedAtByTenant.value };
        delete tCopy[tenantId];
        fetchedAtByTenant.value = tCopy;
        if (loadedForTenantId.value === tenantId) loadedForTenantId.value = null;
    }

    async function fetchForTenant(tenantId, { force = false, maxAgeMs = DEFAULT_TTL_MS } = {}) {
        if (!tenantId) return;

        // V#18 — usa TTL real: cache válido apenas se age < maxAgeMs
        const cached = featuresByTenant.value?.[tenantId];
        const fetchedAt = fetchedAtByTenant.value?.[tenantId] || 0;
        const age = Date.now() - fetchedAt;
        const cacheValid = !force && cached && (maxAgeMs === 0 || age < maxAgeMs);

        if (cacheValid) {
            loadedForTenantId.value = tenantId;
            return;
        }

        loading.value = true;
        lastError.value = null;

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

            if (error) throw error;

            const map = {};
            for (const row of data || []) map[row.feature_key] = !!row.enabled;

            featuresByTenant.value = {
                ...featuresByTenant.value,
                [tenantId]: map
            };
            fetchedAtByTenant.value = {
                ...fetchedAtByTenant.value,
                [tenantId]: Date.now()
            };

            loadedForTenantId.value = tenantId;
            lastFetchedAt.value = new Date().toISOString();
        } catch (e) {
            lastError.value = e;
            // importante: se falhar, mantém cache anterior (se existir)
            // e relança para a página poder mostrar toast se quiser
            throw e;
        } finally {
            loading.value = false;
        }
    }

    /**
     * setForTenant — agora roteia tudo via RPC set_tenant_feature_exception.
     * Autorização e validação ficam no servidor (V#34 Opção B2):
     *   - tenant_admin pode desligar feature do plano e religar
     *   - saas_admin pode tudo + override positivo fora do plano (reason obrigatório)
     */
    async function setForTenant(tenantId, key, enabled, { reason = null } = {}) {
        if (!tenantId) throw new Error('tenantId missing');
        if (!key) throw new Error('feature_key missing');

        lastError.value = null;

        const { data, error } = await supabase.rpc('set_tenant_feature_exception', {
            p_tenant_id: tenantId,
            p_feature_key: key,
            p_enabled: !!enabled,
            p_reason: reason
        });

        if (error) {
            lastError.value = error;
            throw error;
        }

        // Atualiza cache local do tenant
        const current = getTenantMap(tenantId);
        featuresByTenant.value = {
            ...featuresByTenant.value,
            [tenantId]: { ...current, [key]: !!enabled }
        };
        loadedForTenantId.value = tenantId;

        return data;
    }

    // (opcional) útil pra debug rápido na tela
    const currentFeatures = computed(() => getTenantMap(loadedForTenantId.value));

    return {
        loading,
        lastError,
        lastFetchedAt,

        loadedForTenantId,
        featuresByTenant,
        currentFeatures,

        isEnabled,
        invalidate,
        fetchForTenant,
        setForTenant
    };
});
