<?php

use App\Services\Datev\DatevCommandSyncLogger;
use Illuminate\Console\Events\CommandFinished;
use Illuminate\Console\Events\CommandStarting;
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Schedule;

/*
|--------------------------------------------------------------------------
| Zentrales DATEV-SyncRun-Logging
|--------------------------------------------------------------------------
|
| Jeder Artisan-Command mit dem Präfix "datev:" wird automatisch im
| vorhandenen SyncRun-Log protokolliert.
|
| Das betrifft manuelle Aufrufe, Scheduler-Aufrufe und DATEV-Commands,
| die später über den normalen Queue-Worker per Artisan::call ausgeführt
| werden.
|
| Fehler im Logging werden intern abgefangen und dürfen weder einen
| DATEV-Lauf noch den produktiven Bestellimport stoppen.
*/

Event::listen(
    CommandStarting::class,
    static function (
        CommandStarting $event
    ): void {
        DatevCommandSyncLogger::started(
            $event
        );
    }
);

Event::listen(
    CommandFinished::class,
    static function (
        CommandFinished $event
    ): void {
        DatevCommandSyncLogger::finished(
            $event
        );
    }
);

Artisan::command('inspire', function () {
    $this->comment(
        Inspiring::quote()
    );
})->purpose('Display an inspiring quote');

/*
|--------------------------------------------------------------------------
| Sync-Zyklen websale-connect
|--------------------------------------------------------------------------
| Taktung bewusst versetzt (Minuten-Offsets), damit die Läufe aufeinander
| aufbauen statt zu kollidieren:
|
|   :00/:05/:10/…  Pull (5-Min-Raster) – importiert Bestellungen, löst je
|                  Bestellung den Post-Order-Stock-Push aus. Die Versand-
|                  status-Prüfung des Reservierungs-Overlays läuft dabei
|                  automatisch mit (kein eigener Status-Cron nötig).
|   :00 gerade Std Artikel-Map-Build über die robuste /stocks-Route –
|                  liegt VOR dem Voll-Push, damit dessen Chunks garantiert
|                  eine warme Map vorfinden (auch wenn /items zickt).
|   :18 gerade Std Voll-Abgleich – NACH dem :15-Pull-Slot, damit frische
|                  Bestellungen bereits importiert sind und das Overlay sie
|                  kennt, bevor absolut geschrieben wird.
|
| withoutOverlapping wirkt je Command (Pull vs. Push schützen sich also
| nicht gegenseitig – deshalb die Offsets). Live-Senden des Pushs hängt
| zusätzlich am Schalter STOCK_PUSH_ENABLED.
*/

// Bestellungen abholen & importieren (Kern-Takt des Systems).
Schedule::command('websale:orders:pull --write')->everyFiveMinutes()->withoutOverlapping();

// Artikel-Map (ItemId→SKU) vor jedem Voll-Push frisch über /stocks bauen.
Schedule::command('jtl:itemmap:build --stocks')->cron('0 */2 * * *')->withoutOverlapping();

// Voll-Abgleich des Bestands JTL → Websale (chunk-basiert über die Queue).
//
// PAUSIERT 2026-08-14: Die Artikel-Map (ItemId→SKU) ist verlorengegangen. Der
// Voll-Push reihte im 5-Minuten-Takt Chunks ein, die den Worker blockierten und
// den Bestellimport (ImportWebsaleOrderJob) aussperrten. Wieder aktivieren,
// sobald die Map über "jtl:itemmap:build --stocks" verifiziert steht.
// Schedule::command('websale:stock:push --queue --chunk=200')->cron('*/5 * * * *')->withoutOverlapping();

/*
|--------------------------------------------------------------------------
| DATEV-Automatik
|--------------------------------------------------------------------------
|
| Der Scheduler legt den täglichen DATEV-Lauf in die normale Queue.
| Der vorhandene Queue-Worker übernimmt anschließend die Verarbeitung.
|
| Es werden die letzten zwei vollständig abgeschlossenen Tage erneut
| synchronisiert. Durch den idempotenten DATEV-Sync entstehen dabei keine
| doppelten Aufträge.
*/

Schedule::command(
    'datev:queue-daily-sync --days=2'
)
    ->dailyAt('03:20')
    ->timezone('Europe/Berlin')
    ->withoutOverlapping(120)
    ->appendOutputTo(
        storage_path(
            'logs/datev-scheduler.log'
        )
    );

/*
 * Am Monatsanfang wird der vollständige Vormonat für alle aktiven
 * DATEV-Filialen in die normale Queue gelegt. Der Queue-Job und der
 * Tages-Sync teilen sich denselben DATEV-Lock.
 */
Schedule::command(
    'datev:queue-previous-month-generate'
)
    ->monthlyOn(
        (int) config(
            'datev_automation.monthly_generate.day',
            1
        ),
        (string) config(
            'datev_automation.monthly_generate.time',
            '05:30'
        )
    )
    ->timezone(
        (string) config(
            'datev_automation.timezone',
            'Europe/Berlin'
        )
    )
    ->withoutOverlapping(180)
    ->appendOutputTo(
        storage_path(
            'logs/datev-scheduler.log'
        )
    );

/*
|--------------------------------------------------------------------------
| Überwachung & Hauswirtschaft
|--------------------------------------------------------------------------
*/

// Nächtlicher Drift-Wächter.
Schedule::command(
    'websale:stock:compare --all --only-diff'
)
    ->dailyAt('04:40')
    ->withoutOverlapping()
    ->appendOutputTo(
        storage_path(
            'logs/stock-compare.log'
        )
    );

// Worker täglich durchstarten.
Schedule::command(
    'queue:restart'
)
    ->dailyAt('04:55');

// Fehlgeschlagene Jobs nach 7 Tagen aus failed_jobs räumen.
Schedule::command(
    'queue:prune-failed --hours=168'
)
    ->dailyAt('05:05');

// Alte SyncRun-Protokolle löschen.
Schedule::command(
    'model:prune'
)
    ->dailyAt('05:10');