@echo off
setlocal EnableExtensions
chcp 65001 >nul
title Limpeza do Spooler de Impressão

:: ============================================================================
::  LimparSpooler.bat
::  Destrava a fila de impressão: para o Spooler, remove os trabalhos presos,
::  reinicia o serviço e valida o resultado.
::
::  Uso:
::    LimparSpooler.bat          -> modo interativo (com pausas e cores)
::    LimparSpooler.bat /s       -> modo silencioso (sem pausas; ideal p/ GPO,
::                                  tarefa agendada ou execução remota)
::
::  Códigos de saída:
::    0 = sucesso
::    1 = sem privilégios de administrador / UAC negado
::    2 = não foi possível parar o Spooler
::    3 = arquivos não puderam ser removidos da fila
::    4 = não foi possível iniciar o Spooler
::
::  Log: %ProgramData%\LimpezaSpooler\limpeza_spooler.log
:: ============================================================================

:: ---------------------------------------------------------------- Parâmetros
set "SILENCIOSO=0"
for %%P in (%*) do (
    if /i "%%~P"=="/s"          set "SILENCIOSO=1"
    if /i "%%~P"=="/silencioso" set "SILENCIOSO=1"
)

:: ---------------------------------------------------------------- Cores ANSI
for /f %%a in ('echo prompt $E ^| cmd') do set "ESC=%%a"
set "C_RST=%ESC%[0m"
set "C_TIT=%ESC%[96m"
set "C_OK=%ESC%[92m"
set "C_AVS=%ESC%[93m"
set "C_ERR=%ESC%[91m"
set "C_DIM=%ESC%[90m"

:: ------------------------------------------------- Verificação de privilégio
fltmc >nul 2>&1
if errorlevel 1 goto :elevar
goto :inicio

:elevar
if /i "%~1"=="__elevado" (
    echo %C_ERR%[ERRO]%C_RST% Não foi possível obter privilégios de administrador.
    if "%SILENCIOSO%"=="0" pause
    exit /b 1
)
echo.
echo %C_AVS%Solicitando privilégios de administrador (UAC)...%C_RST%
powershell -NoProfile -ExecutionPolicy Bypass -Command "try { Start-Process -FilePath '%~f0' -ArgumentList '__elevado %*' -Verb RunAs -ErrorAction Stop; exit 0 } catch { exit 1 }"
if errorlevel 1 (
    echo %C_ERR%[ERRO]%C_RST% Elevação cancelada pelo usuário ou bloqueada pela política.
    if "%SILENCIOSO%"=="0" pause
    exit /b 1
)
exit /b 0

:: ============================================================================
:inicio
cd /d "%~dp0"
set "RC=0"
set "FAX_ATIVO=0"

:: ---------------------------------------------------------------- Log
set "LOGDIR=%ProgramData%\LimpezaSpooler"
if not exist "%LOGDIR%" mkdir "%LOGDIR%" >nul 2>&1
set "LOG=%LOGDIR%\limpeza_spooler.log"
call :log "================ INÍCIO (usuário: %USERNAME% / máquina: %COMPUTERNAME%) ================"

cls
echo.
echo %C_TIT%  ╔══════════════════════════════════════════════════════════╗%C_RST%
echo %C_TIT%  ║          LIMPEZA DO SPOOLER DE IMPRESSÃO                 ║%C_RST%
echo %C_TIT%  ╚══════════════════════════════════════════════════════════╝%C_RST%
echo %C_DIM%   Máquina: %COMPUTERNAME%   ^|   Log: %LOG%%C_RST%
echo.

:: ------------------------------------------- [1/6] Localiza a pasta do spool
echo %C_TIT%[1/6]%C_RST% Localizando a pasta de spool...
set "SPOOLDIR="
for /f "tokens=2,*" %%A in ('reg query "HKLM\SYSTEM\CurrentControlSet\Control\Print\Printers" /v DefaultSpoolDirectory 2^>nul ^| find /i "DefaultSpoolDirectory"') do set "SPOOLDIR=%%B"
if not defined SPOOLDIR set "SPOOLDIR=%SystemRoot%\System32\spool\PRINTERS"
if not exist "%SPOOLDIR%\" (
    echo       %C_AVS%Pasta não encontrada, usando o padrão do Windows.%C_RST%
    set "SPOOLDIR=%SystemRoot%\System32\spool\PRINTERS"
)
echo       %C_OK%OK%C_RST% %SPOOLDIR%
call :log "Pasta de spool: %SPOOLDIR%"

:: ------------------------------------------- [2/6] Inventário da fila
echo %C_TIT%[2/6]%C_RST% Verificando trabalhos na fila...
call :contar_arquivos
set "TRAB_ANTES=%QTD_SHD%"
set "ARQ_ANTES=%QTD_TOTAL%"
if "%ARQ_ANTES%"=="0" (
    echo       %C_OK%Nenhum arquivo na fila%C_RST% ^(o reinício do serviço ainda pode ajudar^).
) else (
    echo       %C_AVS%%TRAB_ANTES% trabalho^(s^) / %ARQ_ANTES% arquivo^(s^) encontrados na fila.%C_RST%
)
call :log "Antes: %TRAB_ANTES% trabalho(s), %ARQ_ANTES% arquivo(s)"

sc query Fax 2>nul | findstr /c:"RUNNING" >nul && set "FAX_ATIVO=1"

:: ------------------------------------------- [3/6] Para o Spooler
echo %C_TIT%[3/6]%C_RST% Parando o serviço Spooler...
net stop spooler /y >nul 2>&1
set "TENTATIVAS=0"
:aguarda_parada
sc query spooler | findstr /c:"STOPPED" >nul && goto :parado
set /a TENTATIVAS+=1
if %TENTATIVAS% geq 15 goto :forcar_parada
call :esperar 1
goto :aguarda_parada

:forcar_parada
echo       %C_AVS%O serviço não respondeu. Forçando encerramento...%C_RST%
call :log "Spooler não parou em 15s - forçando taskkill"
taskkill /f /im spoolsv.exe >nul 2>&1
taskkill /f /im PrintIsolationHost.exe >nul 2>&1
call :esperar 2
sc query spooler | findstr /c:"STOPPED" >nul && goto :parado
echo       %C_ERR%[ERRO] Não foi possível parar o Spooler.%C_RST%
call :log "ERRO: Spooler não parou"
set "RC=2"
goto :fim

:parado
:: Garante que processos de isolamento de driver não seguram arquivos
taskkill /f /im PrintIsolationHost.exe >nul 2>&1
echo       %C_OK%OK%C_RST% Spooler parado.
call :log "Spooler parado"

:: ------------------------------------------- [4/6] Limpa a fila
echo %C_TIT%[4/6]%C_RST% Removendo trabalhos presos...
del /f /q "%SPOOLDIR%\*.*" >nul 2>&1
call :contar_arquivos
if not "%QTD_TOTAL%"=="0" (
    call :esperar 2
    del /f /q "%SPOOLDIR%\*.*" >nul 2>&1
    call :contar_arquivos
)
if "%QTD_TOTAL%"=="0" (
    echo       %C_OK%OK%C_RST% Fila limpa.
    call :log "Fila limpa"
) else (
    echo       %C_ERR%[ERRO] %QTD_TOTAL% arquivo^(s^) não puderam ser removidos.%C_RST%
    call :log "ERRO: %QTD_TOTAL% arquivo(s) permaneceram na fila"
    set "RC=3"
)

:: ------------------------------------------- [5/6] Inicia o Spooler
echo %C_TIT%[5/6]%C_RST% Iniciando o serviço Spooler...
sc qc spooler | findstr /c:"DISABLED" >nul && (
    echo       %C_AVS%Serviço estava DESATIVADO. Reconfigurando para automático...%C_RST%
    sc config spooler start= auto >nul
    call :log "Spooler estava desativado - reconfigurado para automático"
)
net start spooler >nul 2>&1
set "TENTATIVAS=0"
:aguarda_inicio
sc query spooler | findstr /c:"RUNNING" >nul && goto :iniciado
set /a TENTATIVAS+=1
if %TENTATIVAS% geq 15 goto :falha_inicio
if %TENTATIVAS%==5 net start spooler >nul 2>&1
call :esperar 1
goto :aguarda_inicio

:falha_inicio
echo       %C_ERR%[ERRO] O Spooler não iniciou.%C_RST%
call :log "ERRO: Spooler não iniciou"
set "RC=4"
goto :fim

:iniciado
echo       %C_OK%OK%C_RST% Spooler em execução.
call :log "Spooler iniciado"

:: ------------------------------------------- [6/6] Serviços dependentes
echo %C_TIT%[6/6]%C_RST% Restaurando serviços dependentes...
if "%FAX_ATIVO%"=="1" (
    net start Fax >nul 2>&1 && (
        echo       %C_OK%OK%C_RST% Serviço de Fax reiniciado.
        call :log "Fax reiniciado"
    ) || (
        echo       %C_AVS%Não foi possível reiniciar o Fax.%C_RST%
        call :log "AVISO: Fax não reiniciou"
    )
) else (
    echo       %C_DIM%Nenhum serviço dependente para restaurar.%C_RST%
)

:: ============================================================================
:fim
echo.
echo %C_TIT%  ──────────────────────────── RESUMO ────────────────────────────%C_RST%
echo    Trabalhos removidos : %TRAB_ANTES%
echo    Arquivos removidos  : %ARQ_ANTES%
if "%RC%"=="0" (
    echo    Resultado           : %C_OK%SUCESSO - impressão liberada%C_RST%
) else (
    echo    Resultado           : %C_ERR%FALHA ^(código %RC%^) - veja o log%C_RST%
)
echo %C_TIT%  ────────────────────────────────────────────────────────────────%C_RST%
call :log "FIM - código de saída %RC%"
echo.
if "%SILENCIOSO%"=="0" (
    echo %C_DIM%Pressione qualquer tecla para fechar...%C_RST%
    pause >nul
)
endlocal & exit /b %RC%

:: ============================================================================
::  Sub-rotinas
:: ============================================================================
:contar_arquivos
set "QTD_SHD=0"
set "QTD_TOTAL=0"
for %%F in ("%SPOOLDIR%\*.SHD") do set /a QTD_SHD+=1
for %%F in ("%SPOOLDIR%\*.*")   do set /a QTD_TOTAL+=1
exit /b

:esperar
:: ping em vez de timeout: funciona mesmo sem console interativo (GPO/agendador)
set /a "_n=%~1+1"
ping -n %_n% 127.0.0.1 >nul
exit /b

:log
>>"%LOG%" echo [%date% %time:~0,8%] %~1
exit /b
