/*
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/services/DocumentSignatures.service.js
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
*/
import { supabase } from '@/lib/supabase/client';

import { tenantDb } from '@/lib/supabase/tenantClient';
// ── Helpers ──────────────────────────────────────────────────

async function getOwnerId() {
    const { data, error } = await supabase.auth.getUser();
    if (error) throw error;
    const uid = data?.user?.id;
    if (!uid) throw new Error('Sessão inválida.');
    return uid;
}

async function getActiveTenantId(uid) {
    const { data, error } = await supabase
        .from('tenant_members')
        .select('tenant_id')
        .eq('user_id', uid)
        .eq('status', 'active')
        .order('created_at', { ascending: false })
        .limit(1)
        .single();
    if (error) throw error;
    if (!data?.tenant_id) throw new Error('Tenant não encontrado.');
    return data.tenant_id;
}

// ── Hash do documento ───────────────────────────────────────

/**
 * Gera hash SHA-256 de um ArrayBuffer (conteudo do arquivo).
 */
export async function hashDocument(arrayBuffer) {
    const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

// ── Criar solicitacao de assinatura ─────────────────────────

/**
 * Cria uma ou mais solicitacoes de assinatura para um documento.
 *
 * @param {string} documentoId - UUID do documento
 * @param {Array} signatarios  - [{ tipo, nome, email, id? }]
 *   tipo: 'paciente' | 'responsavel_legal' | 'terapeuta'
 */
export async function createSignatureRequests(documentoId, signatarios = []) {
    if (!documentoId) throw new Error('Documento não informado.');
    if (!signatarios.length) throw new Error('Ao menos um signatário é necessário.');

    const ownerId = await getOwnerId();
    const tenantId = await getActiveTenantId(ownerId);

    const rows = signatarios.map((s, idx) => ({
        documento_id: documentoId,
        signatario_tipo: s.tipo || 'paciente',
        signatario_id: s.id || null,
        signatario_nome: s.nome || null,
        signatario_email: s.email || null,
        ordem: idx + 1,
        status: 'pendente'
    }));

    const { data, error } = await tenantDb().from('document_signatures')
        .insert(rows)
        .select('*');

    if (error) throw error;
    return data || [];
}

// ── Registrar assinatura ────────────────────────────────────

/**
 * Registra que um signatario assinou o documento.
 *
 * @param {string} signatureId  - UUID da solicitacao de assinatura
 * @param {object} meta         - { ip, user_agent, hash_documento }
 */
export async function registerSignature(signatureId, meta = {}) {
    if (!signatureId) throw new Error('ID da assinatura inválido.');

    const { data, error } = await tenantDb().from('document_signatures')
        .update({
            status: 'assinado',
            ip: meta.ip || null,
            user_agent: meta.user_agent || null,
            assinado_em: new Date().toISOString(),
            hash_documento: meta.hash_documento || null
        })
        .eq('id', signatureId)
        .select('*')
        .single();

    if (error) throw error;
    return data;
}

// ── Listar assinaturas de um documento ──────────────────────

export async function listSignatures(documentoId) {
    if (!documentoId) return [];

    const { data, error } = await tenantDb().from('document_signatures')
        .select('*')
        .eq('documento_id', documentoId)
        .order('ordem', { ascending: true });

    if (error) throw error;
    return data || [];
}

// ── Status geral do documento ───────────────────────────────

/**
 * Retorna o status consolidado de assinaturas de um documento.
 *
 * @returns {{ total, assinados, pendentes, status }}
 *   status: 'completo' | 'parcial' | 'pendente' | 'sem_assinaturas'
 */
export async function getSignatureStatus(documentoId) {
    const sigs = await listSignatures(documentoId);
    if (!sigs.length) return { total: 0, assinados: 0, pendentes: 0, status: 'sem_assinaturas' };

    const assinados = sigs.filter(s => s.status === 'assinado').length;
    const pendentes = sigs.length - assinados;

    let status = 'pendente';
    if (assinados === sigs.length) status = 'completo';
    else if (assinados > 0) status = 'parcial';

    return { total: sigs.length, assinados, pendentes, status };
}

// ── Recusar assinatura ──────────────────────────────────────

export async function refuseSignature(signatureId) {
    if (!signatureId) throw new Error('ID da assinatura inválido.');

    const { data, error } = await tenantDb().from('document_signatures')
        .update({
            status: 'recusado',
            atualizado_em: new Date().toISOString()
        })
        .eq('id', signatureId)
        .select('*')
        .single();

    if (error) throw error;
    return data;
}

// ── Assinar via portal (paciente logado) ─────────────────────
//
// IP e user-agent são capturados SERVER-SIDE pela RPC via
// inet_client_addr() e current_setting('request.headers'). O cliente
// só passa o hash SHA-256 do PDF (gerado via hashDocument()) pra
// garantir integridade do documento no momento da assinatura.
//
export async function signByPortal(tenantId, signatureId, hashDocumento = null) {
    if (!signatureId) throw new Error('ID da assinatura inválido.');
    if (!tenantId) throw new Error('Tenant da assinatura não resolvido.');

    const { data, error } = await supabase.rpc('sign_document_by_signature_id', {
        p_tenant_id: tenantId,
        p_signature_id: signatureId,
        p_hash_documento: hashDocumento || null
    });
    if (error) throw error;
    return data;
}

// ── Assinar via token público (share link) ──────────────────
//
// Para signatários não-logados acessando via /shared/document/:token.
// p_signature_id é opcional — quando o documento tem múltiplos
// signatários, identifica qual deles está assinando. Quando há apenas
// um pendente, deixa null e o backend resolve.
//
export async function signByToken(token, signatureId = null, hashDocumento = null) {
    if (!token) throw new Error('Token inválido.');

    const { data, error } = await supabase.rpc('sign_document_by_token', {
        p_token: token,
        p_signature_id: signatureId || null,
        p_hash_documento: hashDocumento || null
    });
    if (error) throw error;
    return data;
}

// ── Listar minhas assinaturas (portal do paciente) ──────────
//
// Wrapper sobre RPC list_my_signatures. Resolve auth.uid() server-side
// e cruza por signatario_id / email / patient.user_id pra encontrar
// todas as assinaturas que pertencem ao usuário logado. Inclui
// share_token p/ apontar direto pra /shared/document/:token.
//
export async function listMySignatures(statusFilter = null) {
    const { data, error } = await supabase.rpc('list_my_signatures', {
        p_status: Array.isArray(statusFilter) ? statusFilter : null
    });
    if (error) throw error;
    return data || [];
}

// ── Pré-visualizar documento por token (sem assinar) ────────
//
// Usado pela página pública pra carregar info do documento +
// signatários pendentes ANTES do click em "Assinar". Retorna
// { valid, document, signatures, expira_em, usos_restantes }.
//
export async function getSignableDocumentByToken(token) {
    if (!token) throw new Error('Token inválido.');

    const { data, error } = await supabase.rpc('get_signable_document_by_token', {
        p_token: token
    });
    if (error) throw error;
    return data;
}
