<?php

declare(strict_types=1);

// Runner de sincronização das integrações de Realizado (CLI)
// Agora verifica back.integracao_horarios para determinar quais sincronizações executar
// O schedule da hospedagem deve chamar este script A CADA 1 MINUTO
// Exemplo cron: */1 * * * * php /var/www/html/orcamento/public/run_integracoes_schedule.php
//
// Observação: este script NÃO depende de usuário logado e É APENAS CLI

if (PHP_SAPI !== 'cli') {
	http_response_code(403);
	echo "Este endpoint é apenas para CLI.\n";
	exit(1);
}

require_once dirname(__DIR__) . '/app/config/db.php';
require_once dirname(__DIR__) . '/app/lib/origem_sync_lib.php';

// Importa funções de sincronização sem executar o switch do realized_actions
define('HOME_ACTIONS_LOADING', true);
require_once dirname(__DIR__) . '/app/modules/realizado_actions.php';

function acquireLock(string $lockFile) {
	$dir = dirname($lockFile);
	if (!is_dir($dir)) {
		@mkdir($dir, 0777, true);
	}
	$fp = @fopen($lockFile, 'c+');
	if (!$fp) return null;
	if (!flock($fp, LOCK_EX | LOCK_NB)) {
		@fclose($fp);
		return null;
	}
	return $fp;
}

function releaseLock($fp): void {
	if (!$fp) return;
	@flock($fp, LOCK_UN);
	@fclose($fp);
}

$now = new DateTimeImmutable('now');
$minuteKey = $now->format('Y-m-d H:i');

$lockDir = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'logs' . DIRECTORY_SEPARATOR . 'scheduler';

// Garante que o diretório de logs existe
if (!is_dir($lockDir)) {
	if (!@mkdir($lockDir, 0777, true)) {
		echo "ERRO: Não foi possível criar o diretório de logs: {$lockDir}\n";
		exit(1);
	}
}

echo "[" . $now->format('Y-m-d H:i:s') . "] Iniciando runner de sincronização...\n";
echo "[" . $now->format('Y-m-d H:i:s') . "] Diretório de logs: {$lockDir}\n";

$rootLockFile = $lockDir . DIRECTORY_SEPARATOR . 'integracoes_schedule_runner.lock';
$rootLock = acquireLock($rootLockFile);
if (!$rootLock) {
	fwrite(STDERR, "[" . $now->format('Y-m-d H:i:s') . "] Runner já está em execução (lock ativo).\n");
	exit(0);
}

try {
	echo "[" . $now->format('Y-m-d H:i:s') . "] Buscando integrações agendadas...\n";
	
	$hora_atual = (int)$now->format('H');
	$minuto_atual = (int)$now->format('i');
	
	// Query: buscar integrações com horário agendado para AGORA
	// - Conexão/API: possuem horários próprios
	// - Origem: herda horários das integrações de referência (via integracao_conexao)
	$sql = "
		SELECT DISTINCT 
			i.cdintegracao, 
			i.dsintegracao,
			i.fltipo
		FROM back.integracao i
		INNER JOIN back.integracao_horarios ih 
			ON i.cdintegracao = ih.cdintegracao
		WHERE 
			i.flativo = true
			AND ih.flativo = true
			AND ih.hora = :hora
			AND ih.minuto = :minuto

		UNION

		SELECT DISTINCT
			iorigem.cdintegracao,
			iorigem.dsintegracao,
			iorigem.fltipo
		FROM back.integracao iorigem
		INNER JOIN back.integracao_conexao ic
			ON iorigem.cdintegracao = ic.cdintegracao
		INNER JOIN back.integracao_horarios ih2
			ON ic.cdintegracao_conexao = ih2.cdintegracao
		WHERE
			iorigem.flativo = true
			AND iorigem.fltipo = 'origem'
			AND ih2.flativo = true
			AND ih2.hora = :hora2
			AND ih2.minuto = :minuto2

		ORDER BY cdintegracao
	";

	$stmt = $pdo->prepare($sql);
	$stmt->execute([':hora' => $hora_atual, ':minuto' => $minuto_atual, ':hora2' => $hora_atual, ':minuto2' => $minuto_atual]);
	$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

	if (!$rows) {
		echo "[" . $now->format('Y-m-d H:i:s') . "] Nenhuma integração agendada para este horário ({$hora_atual}:{$minuto_atual}).\n";
		exit(0);
	}
	
	echo "[" . $now->format('Y-m-d H:i:s') . "] Encontradas " . count($rows) . " integração(ões) para executar\n";

	$executadas = 0;
	$totalInseridos = 0;
	$totalIgnorados = 0;
	$totalErros = 0;

	foreach ($rows as $r) {
		$id = (int)($r['cdintegracao'] ?? 0);
		if ($id <= 0) continue;

		$nome = (string)($r['dsintegracao'] ?? ('Integração ' . $id));

		// Anti-repetição no mesmo minuto por integração
		$stateFile = $lockDir . DIRECTORY_SEPARATOR . 'integracao_' . $id . '_last_run.txt';
		$last = '';
		if (file_exists($stateFile)) {
			$last = @file_get_contents($stateFile);
			$last = is_string($last) ? trim($last) : '';
		}
		if ($last === $minuteKey) {
			echo "[" . $now->format('Y-m-d H:i:s') . "] Integração #{$id} já executada neste minuto, pulando\n";
			continue;
		}

		// Lock por integração
		$intLockFile = $lockDir . DIRECTORY_SEPARATOR . 'integracao_' . $id . '.lock';
		$intLock = acquireLock($intLockFile);
		if (!$intLock) {
			echo "[" . $now->format('Y-m-d H:i:s') . "] Integração #{$id} já está em execução (lock), pulando\n";
			continue;
		}

		try {
			echo "[" . $now->format('Y-m-d H:i:s') . "] Executando integração #{$id} ({$nome})...\n";

			$tipoInt = $r['fltipo'] ?? 'conexao';
			
			if ($tipoInt === 'origem') {
				// Integrações "origem": sincronizar dados genéricos para back.origem_dados
				$res = sincronizarOrigemSchedule($id, $pdo);
			} else {
				// Integrações "conexao"/"api": sincronizar realizado
				// skipRefresh=true porque faremos o refresh uma única vez ao final (mais eficiente)
				$res = sincronizarIntegracaoAgora($id, null, null, null, 'automatica', true);
			}

			$ins = (int)($res['total'] ?? 0);
			$ign = (int)($res['ignorados'] ?? 0);
			$err = (int)($res['erros'] ?? 0);

			$executadas++;
			$totalInseridos += $ins;
			$totalIgnorados += $ign;
			$totalErros += $err;

			// Salva timestamp da última execução
			if (@file_put_contents($stateFile, $minuteKey) === false) {
				echo "  -> Aviso: Não foi possível salvar state file\n";
			}

			echo "  -> OK (inseridos={$ins}, ignorados={$ign}, erros={$err})\n";

			// ✨ CASCADING: Após sincronizar conexão/api, disparar origens vinculadas
			if ($tipoInt !== 'origem') {
				$origensVinculadas = buscarOrigensVinculadasSchedule($id, $pdo);
				if (!empty($origensVinculadas)) {
					echo "  -> Cascading: " . count($origensVinculadas) . " origem(ns) vinculada(s)\n";
					foreach ($origensVinculadas as $orRow) {
						$orId = (int)$orRow['cdintegracao'];
						$orNome = $orRow['dsintegracao'];

						// Anti-repetição: verifica se esta origem já foi executada neste minuto
						$orStateFile = $lockDir . DIRECTORY_SEPARATOR . 'integracao_' . $orId . '_last_run.txt';
						$orLast = '';
						if (file_exists($orStateFile)) {
							$orLast = @file_get_contents($orStateFile);
							$orLast = is_string($orLast) ? trim($orLast) : '';
						}
						if ($orLast === $minuteKey) {
							echo "     -> Origem #{$orId} ({$orNome}): já executada neste minuto, pulando\n";
							continue;
						}

						try {
							echo "     -> Origem #{$orId} ({$orNome})...\n";
							$resOr = sincronizarOrigemSchedule($orId, $pdo);
							$orIns = (int)($resOr['total'] ?? 0);
							$orIgn = (int)($resOr['ignorados'] ?? 0);
							$orErr = (int)($resOr['erros'] ?? 0);
							$executadas++;

							// Salvar state para anti-repetição
							@file_put_contents($orStateFile, $minuteKey);

							echo "        OK (inseridos={$orIns}, ignorados={$orIgn}, erros={$orErr})\n";
						} catch (Throwable $oe) {
							echo "        ERRO: " . $oe->getMessage() . "\n";
						}
					}
				}
			}
		} catch (Throwable $e) {
			echo "  -> ERRO: " . $e->getMessage() . "\n";
			fwrite(STDERR, "[" . $now->format('Y-m-d H:i:s') . "] ERRO na integração #{$id}: " . $e->getMessage() . "\n");
		} finally {
			releaseLock($intLock);
		}
	}

	if ($executadas > 0) {
		echo "[" . $now->format('Y-m-d H:i:s') . "] Consolidando views...\n";
		$consol = refreshMaterializedViewsRealizado($pdo);
		if (!($consol['ok'] ?? false)) {
			echo "  -> Consolidação falhou\n";
			fwrite(STDERR, "[" . $now->format('Y-m-d H:i:s') . "] Consolidação falhou.\n");
		} else {
			echo "  -> Consolidação OK (views_atualizadas=" . (int)($consol['views_atualizadas'] ?? 0) . ")\n";
		}
	}

	echo "[" . $now->format('Y-m-d H:i:s') . "] Finalizado. Executadas={$executadas}, inseridos={$totalInseridos}, ignorados={$totalIgnorados}, erros={$totalErros}\n";
} catch (Throwable $e) {
	echo "[" . $now->format('Y-m-d H:i:s') . "] ERRO FATAL: " . $e->getMessage() . "\n";
	fwrite(STDERR, "[" . $now->format('Y-m-d H:i:s') . "] ERRO FATAL: " . $e->getMessage() . "\n");
} finally {
	releaseLock($rootLock);
}

/**
 * Busca integrações do tipo "origem" que referenciam uma integração conexão/api
 * Delegado para lib compartilhada
 */
function buscarOrigensVinculadasSchedule(int $cdintegracao, PDO $pdo): array {
	return origemBuscarVinculadas($cdintegracao, $pdo);
}

/**
 * Sincronização de integrações do tipo "origem" para uso no schedule
 * Delegado para lib compartilhada, com output de log para CLI
 */
function sincronizarOrigemSchedule(int $cdintegracao, PDO $pdo): array {
	$res = origemExecutarSincronizacao($cdintegracao, $pdo);

	// Exibir mensagens detalhadas no log CLI
	if (!empty($res['mensagens'])) {
		foreach ($res['mensagens'] as $m) {
			echo "    -> {$m}\n";
		}
	}

	return [
		'total' => $res['total'] ?? 0,
		'ignorados' => $res['ignorados'] ?? 0,
		'erros' => $res['erros'] ?? 0
	];
}
