-- ============================================================================
-- RPC accept_tenant_invite — destrava o fluxo de aceitar convite
-- ----------------------------------------------------------------------------
-- Recebe o token UUID do invite. Em uma transação (SECURITY DEFINER):
--   1. Lê invite ATIVO (não accepted, não revoked, não expired)
--   2. INSERT em tenant_members com role do invite + user_id = auth.uid()
--   3. UPDATE invite com accepted_at + accepted_by
--
-- Retorna jsonb { ok, tenant_id, role } em sucesso ou throw com mensagem PT-BR.
--
-- Chamada pelo features/tenantship/services/tenantInvitesRepository.acceptInvite().
-- Stub anterior tava jogando erro PT-BR explicando isso. Agora funciona.
-- ============================================================================

BEGIN;

CREATE OR REPLACE FUNCTION public.accept_tenant_invite(p_token uuid)
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
    v_uid uuid;
    v_invite record;
    v_existing_member record;
BEGIN
    -- Quem está aceitando — auth.uid() pega do JWT
    v_uid := auth.uid();
    IF v_uid IS NULL THEN
        RAISE EXCEPTION 'Sessão inválida (sem user autenticado).';
    END IF;

    -- 1. Lê invite ativo. Lock via FOR UPDATE pra evitar race.
    SELECT id, tenant_id, email, role, accepted_at, revoked_at, expires_at
      INTO v_invite
      FROM public.tenant_invites
     WHERE token = p_token
     FOR UPDATE;

    IF NOT FOUND THEN
        RAISE EXCEPTION 'Convite não encontrado. Verifique o link.';
    END IF;

    IF v_invite.revoked_at IS NOT NULL THEN
        RAISE EXCEPTION 'Convite revogado pelo administrador.';
    END IF;

    IF v_invite.accepted_at IS NOT NULL THEN
        RAISE EXCEPTION 'Convite já foi aceito anteriormente.';
    END IF;

    IF v_invite.expires_at IS NOT NULL AND v_invite.expires_at < now() THEN
        RAISE EXCEPTION 'Convite expirado. Peça um novo ao administrador.';
    END IF;

    -- 2. Idempotência: se já é membro do tenant, só marca invite aceito.
    SELECT id, role, status
      INTO v_existing_member
      FROM public.tenant_members
     WHERE tenant_id = v_invite.tenant_id
       AND user_id = v_uid
     LIMIT 1;

    IF v_existing_member.id IS NULL THEN
        INSERT INTO public.tenant_members (tenant_id, user_id, role, status)
        VALUES (v_invite.tenant_id, v_uid, v_invite.role, 'active');
    ELSIF v_existing_member.status <> 'active' THEN
        UPDATE public.tenant_members
           SET status = 'active', role = v_invite.role
         WHERE id = v_existing_member.id;
    END IF;
    -- (se já está ativo, deixa como tá — convite aceito não rebaixa)

    -- 3. Marca invite como aceito
    UPDATE public.tenant_invites
       SET accepted_at = now(), accepted_by = v_uid
     WHERE id = v_invite.id;

    RETURN jsonb_build_object(
        'ok', true,
        'tenant_id', v_invite.tenant_id,
        'role', v_invite.role
    );
END;
$$;

COMMENT ON FUNCTION public.accept_tenant_invite(uuid) IS
    'Aceita convite de membership. SECURITY DEFINER pra criar tenant_members em nome do user logado. Lock FOR UPDATE no invite previne race condition.';

-- Permite que qualquer authenticated chame (precisa do token UUID válido pra entrar).
REVOKE ALL ON FUNCTION public.accept_tenant_invite(uuid) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.accept_tenant_invite(uuid) TO authenticated;

COMMIT;
