<?php

namespace App\Console\Commands;

use App\Jobs\AutocountSyncJob;
use App\Services\DataverseService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Throwable;

/**
 * Dispatch a full AutoCount master-data sync for EVERY company that has
 * AutoCount configured (Cloud or Desktop). Intended for a daily 12am cron:
 *
 *   0 0 * * *  cd /path/to/syhc-api && php artisan autocount:daily-sync
 *
 * Each company syncs as a queued AutocountSyncJob (same params as the manual
 * "Sync Now"), so a queue worker must be processing the `jobs` table. Each
 * completed job stamps cr6f2_lastsynctime on its company (#4.1).
 */
class DailyAutoCountSync extends Command
{
    protected $signature = 'autocount:daily-sync
        {--dry-run : List the companies that would sync, dispatch nothing}
        {--spacing=30 : Seconds to stagger between each dispatched company, so the limited AutoCount licence seats (default 5) are not all demanded at once. 0 = dispatch all immediately.}';

    protected $description = 'Dispatch a full AutoCount master-data sync for every AutoCount-configured company (daily cron).';

    public function handle(DataverseService $dv): int
    {
        $dryRun = (bool) $this->option('dry-run');
        $this->line('  <fg=cyan>Mode:</> ' . ($dryRun ? 'dry run' : 'APPLY'));
        $this->newLine();

        try {
            $companies = $dv->get('cr6f2_companies', [
                'select'  => ['cr6f2_companyid', 'cr6f2_name', 'cr6f2_acsynctype', 'cr6f2_acdbname', 'cr6f2_acapiendpoint', 'cr6f2_ackeyid', 'cr6f2_acapikey'],
                'filter'  => "(cr6f2_acsynctype eq 'Cloud' or cr6f2_acsynctype eq 'Desktop') and cr6f2_name ne null and statecode eq 0",
                'orderby' => 'cr6f2_acsynctype desc, cr6f2_name asc',
                'top'     => 500,
            ])['value'] ?? [];
        } catch (Throwable $e) {
            $this->error('Failed to list companies: ' . $e->getMessage());
            return Command::FAILURE;
        }

        $dispatched = 0;
        $skipped    = 0;
        $spacing    = max(0, (int) $this->option('spacing'));
        $queueIndex = 0; // counts only actually-dispatched jobs, for the stagger

        foreach ($companies as $c) {
            $id       = $c['cr6f2_companyid'];
            $name     = $c['cr6f2_name'] ?? '';
            $type     = $c['cr6f2_acsynctype'];
            $endpoint = rtrim($c['cr6f2_acapiendpoint'] ?? '', '/') . '/';
            $apiKey   = $c['cr6f2_acapikey'] ?? '';
            $keyId    = $c['cr6f2_ackeyid']  ?? '';
            $dbName   = $c['cr6f2_acdbname'] ?? '';

            // Same completeness guards as the manual sync endpoint.
            if ($type === 'Cloud' && ($endpoint === '/' || $apiKey === '' || $keyId === '')) {
                $this->warn("  · {$name} — skipped (incomplete Cloud credentials)");
                $skipped++;
                continue;
            }
            if ($type === 'Desktop' && $dbName === '') {
                $this->warn("  · {$name} — skipped (no Desktop database name)");
                $skipped++;
                continue;
            }

            if ($dryRun) {
                $this->line("  <fg=green>+</> {$name} ({$type}) — would sync");
                $dispatched++;
                continue;
            }

            Cache::put("ac_sync_{$id}", ['status' => 'pending', 'started_at' => now()->toISOString(), 'sections' => null], 3600);
            $delaySeconds = $queueIndex * $spacing;
            AutocountSyncJob::dispatch(
                $id,
                $type,
                $type === 'Cloud'   ? $endpoint : null,
                $type === 'Cloud'   ? $apiKey   : null,
                $type === 'Cloud'   ? $keyId    : null,
                $type === 'Desktop' ? $dbName   : null,
                $name,
                null,   // system run — no user GUID
                null,   // full sync (all sections)
                true,   // prune orphans, like the manual full sync
                1,      // attempt
                true,   // isNightly — no queue-worker timeout, no Desktop poll deadline
            )->delay(now()->addSeconds($delaySeconds));
            $when = $delaySeconds > 0 ? " (+{$delaySeconds}s)" : '';
            $this->line("  <fg=green>▶</> {$name} ({$type}) — dispatched{$when}");
            $dispatched++;
            $queueIndex++;
        }

        $this->newLine();
        $verb = $dryRun ? 'would dispatch' : 'dispatched';
        $this->info("Done. {$verb} {$dispatched}, skipped {$skipped}.");
        return Command::SUCCESS;
    }
}
