#!/usr/bin/env php
<?php

declare(strict_types=1);

use App\Core\Database\MigrationRunner;
use App\Core\Support\Env;
use App\Database\Seeds\DemoSeed;
use App\Database\Seeds\PermissionSeed;
use App\Modules\Finance\Application\PaymentReminderService;

require dirname(__DIR__) . '/vendor/autoload.php';

Env::load(dirname(__DIR__) . '/.env');
date_default_timezone_set('UTC');

$command = $argv[1] ?? null;
$runner = new MigrationRunner(dirname(__DIR__) . '/database/migrations');

switch ($command) {
    case 'migrate':
        $runner->run();
        break;

    case 'migrate:rollback':
        $runner->rollbackLast();
        break;

    case 'migrate:status':
        foreach ($runner->status() as $row) {
            printf("%-6s %-55s %s\n", $row['version'], $row['file'], $row['applied'] ? ('aplicada em ' . $row['applied_at']) : 'pendente');
        }
        break;

    case 'seed':
        (new DemoSeed())->run();
        break;

    case 'permissions:sync':
        (new PermissionSeed())->run();
        break;

    case 'key:generate':
        $envPath = dirname(__DIR__) . '/.env';
        $key = base64_encode(random_bytes(32));
        $lines = is_file($envPath) ? file($envPath, FILE_IGNORE_NEW_LINES) : [];
        $found = false;
        foreach ($lines as $i => $line) {
            if (str_starts_with(trim($line), 'APP_KEY=')) {
                $lines[$i] = 'APP_KEY=' . $key;
                $found = true;
                break;
            }
        }
        if (!$found) {
            $lines[] = 'APP_KEY=' . $key;
        }
        file_put_contents($envPath, implode("\n", $lines) . "\n");
        echo "APP_KEY gerada e gravada em .env\n";
        break;

    case 'finance:reminders':
        // Rotina diária (cron): avisos de vencimento por e-mail. Data no fuso de Brasília.
        $today = (new DateTimeImmutable('now', new DateTimeZone('America/Sao_Paulo')))->format('Y-m-d');
        foreach (PaymentReminderService::runAll($today) as $result) {
            printf("empresa %d: %d aviso(s) enviado(s), %d com falha, %d sem e-mail\n", $result['company_id'], $result['sent'], $result['failed'], $result['without_email']);
        }
        break;

    case 'finance:bank-sync':
    case 'finance:inter-sync':
        // Rotina (cron): confere no banco os boletos em aberto, para não depender só do aviso de pagamento. finance:inter-sync é o nome antigo.
        $summary = App\Modules\Finance\Application\BankBillingService::syncPending();
        printf("%d boleto(s) consultado(s), %d baixado(s), %d com erro\n", $summary['checked'], $summary['settled'], $summary['errors']);
        break;

    case 'starter:apply':
        // Cadastros padrão (unidades, formas, condições, plano de contas) só onde faltam.
        // Sem argumento: todos os grupos. Com argumento: só o grupo informado.
        $onlyGroup = isset($argv[2]) ? (int) $argv[2] : null;
        $groups = App\Core\Database\Connection::all(
            'SELECT id, name FROM `groups`' . ($onlyGroup !== null ? ' WHERE id = ?' : '') . ' ORDER BY id',
            $onlyGroup !== null ? [$onlyGroup] : []
        );
        foreach ($groups as $group) {
            $created = App\Modules\Organizations\Application\StarterDataService::applyToGroup((int) $group['id']);
            printf("grupo %d (%s): %s\n", $group['id'], $group['name'], json_encode($created));
        }
        break;

    case 'demo:showcase':
        // Empresa de demonstração (grupo próprio) lançada pelas telas.
        // Uso: demo:showcase <senha do usuário demo> [--ensaio]  (--ensaio desfaz tudo no fim, para testar)
        $rehearsal = in_array('--ensaio', $argv, true);
        $arguments = array_values(array_filter(array_slice($argv, 2), static fn (string $a): bool => $a !== '--ensaio'));
        $password = (string) ($arguments[0] ?? '');
        if ($password === '') {
            fwrite(STDERR, "Informe a senha do usuário de demonstração: php bin/console demo:showcase <senha> [--ensaio]\n");
            exit(1);
        }
        $pdo = App\Core\Database\Connection::pdo();
        if ($rehearsal) {
            $pdo->beginTransaction();
        }
        try {
            foreach ((new App\Database\Seeds\Showcase\ShowcaseSeed($password))->run() as $line) {
                echo '- ' . $line . "\n";
            }
        } finally {
            if ($rehearsal && $pdo->inTransaction()) {
                $pdo->rollBack();
                echo "Ensaio: nada foi gravado.\n";
            }
        }
        break;

    case 'demo:extend':
        // Exemplos das funções novas na demonstração existente (idempotente; rodar a cada publicação).
        foreach ((new App\Database\Seeds\Showcase\ShowcaseSeed(''))->extend() as $line) {
            echo '- ' . $line . "\n";
        }
        break;

    case 'fiscal:normas':
        // Verificador de normas fiscais (rodar diariamente pelo cron do servidor).
        foreach (App\Modules\Fiscal\Application\FiscalNormWatcher::check() as $source => $result) {
            $label = App\Modules\Fiscal\Application\FiscalNormWatcher::SOURCES[$source]['label'];
            if ($result['status'] !== 'ok') {
                echo $label . ': ERRO — ' . $result['message'] . "\n";
                continue;
            }
            echo $label . ': ' . $result['found'] . ' documentos, ' . count($result['new']) . " novo(s) pendente(s)\n";
            foreach ($result['new'] as $title) {
                echo '  + ' . $title . "\n";
            }
        }
        echo 'Pendentes de análise: ' . App\Modules\Fiscal\Application\FiscalNormWatcher::pendingCount() . "\n";
        break;

    case 'group:delete':
        // Exclusão definitiva de um grupo. Uso: group:delete <id> ["nome exato do grupo"] [--executar|--ensaio]
        // Sem nome, só mostra o que seria excluído. --ensaio exclui e desfaz; --executar confirma.
        $groupId = (int) ($argv[2] ?? 0);
        $confirmation = (string) ($argv[3] ?? '');
        $execute = in_array('--executar', $argv, true);
        $rehearsal = in_array('--ensaio', $argv, true);
        if ($groupId <= 0) {
            fwrite(STDERR, "Uso: php bin/console group:delete <id> [\"nome exato do grupo\"] [--executar|--ensaio]\n");
            exit(1);
        }
        try {
            $plan = ($execute || $rehearsal) && $confirmation !== '' && !str_starts_with($confirmation, '--')
                ? App\Modules\Platform\Application\GroupPurgeService::purge($groupId, $confirmation, !$execute)
                : App\Modules\Platform\Application\GroupPurgeService::plan($groupId);
        } catch (RuntimeException $exception) {
            fwrite(STDERR, $exception->getMessage() . "\n");
            exit(1);
        }
        echo 'Grupo ' . $plan['group']['id'] . ' — ' . $plan['group']['name'] . "\n";
        foreach ($plan['tables'] as $table => $count) {
            echo '  ' . $table . ': ' . $count . "\n";
        }
        foreach ($plan['users'] as $user) {
            echo '  usuário excluído: ' . $user['email'] . "\n";
        }
        echo '  arquivos no disco: ' . $plan['files'] . "\n";
        echo $execute ? "Grupo excluído.\n" : ($rehearsal ? "Ensaio: tudo foi desfeito.\n" : "Nada foi alterado (informe o nome exato e --executar para excluir).\n");
        break;

    default:
        fwrite(STDERR, "Uso: php bin/console <migrate|migrate:rollback|migrate:status|seed|permissions:sync|key:generate|finance:reminders|finance:bank-sync|starter:apply [grupo]|demo:showcase <senha> [--ensaio]|demo:extend|group:delete <id> [\"nome\"] [--executar|--ensaio]|fiscal:normas>\n");
        exit(1);
}
