<?php

use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schedule;
use Illuminate\Console\Scheduling\Event;

/**
 * -----------------------------------------------------------------------------
 * Gifticon Platform - Console Routes / Scheduler Registry
 * -----------------------------------------------------------------------------
 *
 * [운영/개발 공통] 스케줄/워커/큐 동작 확인 치트시트
 *
 * ✅ 스케줄 등록 목록 확인
 *   docker exec -it gifticon-app php artisan schedule:list
 *
 * ✅ 스케줄러 컨테이너 프로세스 확인
 *   docker exec -it gifticon-scheduler ps aux
 *
 * ✅ 워커 컨테이너 프로세스 확인
 *   docker exec -it gifticon-worker ps aux
 *
 * ✅ 워커 하트비트 로그 확인 (워커가 큐를 소비하고 있음을 증명)
 *   docker exec -it gifticon-app sh -lc "tail -n 200 storage/logs/laravel.log | grep '\[worker-heartbeat\]' | tail -n 20"
 *
 * ✅ 큐 길이 확인 (default 큐)
 *   docker exec -it gifticon-redis redis-cli LLEN queues:default
 *
 * ✅ 실패 잡 확인
 *   docker exec -it gifticon-app php artisan queue:failed
 *
 * -----------------------------------------------------------------------------
 * [장애 대응 가이드]
 * -----------------------------------------------------------------------------
 * 1) "메일은 되는데 워커가 이상" / "큐가 쌓이기만 함"
 *    - queue:failed 확인 → 실패가 쌓이면 코드/설정 오류 가능
 *    - LLEN queues:default 확인 → 계속 증가하면 워커가 소비 못함
 *    - 워커를 일시적으로 디버그 모드로 실행(컨테이너에서):
 *        docker exec -it gifticon-worker php artisan queue:work -vvv --tries=1 --timeout=90
 *
 * 2) "스케줄이 안 돈다"
 *    - schedule:list로 등록 여부 확인
 *    - gifticon-scheduler 컨테이너가 schedule:work로 떠 있는지 확인
 *    - 스케줄은 등록됐는데 실행 흔적이 없다면: 로그/권한/환경(APP_ENV) 분기 확인
 *
 * 3) "Redis 연결 이상"
 *    - 컨테이너 내부에서 Redis 연결 테스트:
 *        docker exec -it gifticon-worker php -r '$r=new Redis(); var_dump($r->connect("gifticon-redis", 6379, 1)); echo $r->ping().PHP_EOL;'
 *
 * -----------------------------------------------------------------------------
 * 운영 안전장치(추천)
 * -----------------------------------------------------------------------------
 * - 테스트용 스케줄은 APP_ENV=local|development에서만 등록되도록 제한
 * - 운영에서 불필요한 스케줄 로그가 쌓이는 사고 예방
 */

// -----------------------------------------------------------------------------
// 공통: 스케줄 등록 헬퍼 (cron 문자열 기반)
// -----------------------------------------------------------------------------
function registerScheduleCron(string $name, string $cron, $job, array $opt = []): Event
{
    $tz   = $opt['timezone'] ?? config('app.timezone', 'Asia/Seoul');
    $lock = $opt['without_overlapping'] ?? true;

    $event = is_callable($job)
        ? Schedule::call(function () use ($name, $job) {
            try {
                Log::info("[schedule:$name] start");
                $job();
                Log::info("[schedule:$name] done");
            } catch (\Throwable $e) {
                Log::error("[schedule:$name] failed", [
                    'err' => $e->getMessage(),
                ]);
                throw $e;
            }
        })
        : Schedule::command((string) $job);

    // 중요: withoutOverlapping 전에 name 필수
    $event->name($name);

    $event->cron($cron)->timezone($tz);

    // 운영 옵션
    if ($lock) $event->withoutOverlapping();
    if (!empty($opt['on_one_server'])) $event->onOneServer();
    if (!empty($opt['run_in_background'])) $event->runInBackground();

    // 실패 시 로그 남기기 (Laravel 12에서도 지원)
    // NOTE: 잡 실패를 즉시 알기 좋음
    $event->onFailure(function (\Throwable $e) use ($name) {
        Log::error("[schedule:$name] onFailure", [
            'err' => $e->getMessage(),
        ]);
    });

    return $event;
}

// -----------------------------------------------------------------------------
// 운영용(Production 포함): 워커/스케줄러 생존 확인용 Heartbeat
// - 스케줄러가 매 분 실행
// - 큐로 잡을 던지고
// - 워커가 처리하면 로그가 찍힘
// => scheduler + redis + worker 전체 체인이 정상임을 증명
// -----------------------------------------------------------------------------

/*메일 발송 스케줄러*/
registerScheduleCron('admin_mail_dispatch_due', '* * * * *', 'admin-mail:dispatch-due --limit=20', [
    'without_overlapping' => true,
    'on_one_server' => true,        // 스케줄러 컨테이너가 여러개일 수 있으면 유지(1개면 있어도 무해)
    'run_in_background' => true,
]);

registerScheduleCron('marketing_members_stats_daily', '10 3 * * *', 'marketing:members:build-stats', [
    'without_overlapping' => true,
    'on_one_server' => true,
    'run_in_background' => true,
]);






// -----------------------------------------------------------------------------
// Artisan 커맨드 (개발/운영 공통) - 단발성 테스트 도구 호출용
//     docker exec -it gifticon-app php artisan inspire
//     docker exec -it gifticon-app php artisan tick
// -----------------------------------------------------------------------------
Artisan::command('inspire', function () {
    $this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote');

Artisan::command('tick', function () {
    Log::info('[tick] artisan command ok '.now());
    $this->info('tick ok: '.now());
})->purpose('Quick artisan health check');






// -----------------------------------------------------------------------------
// 개발 전용 스케줄/테스트 스케줄 (운영에서 로그 쌓이는 사고 방지)
// -----------------------------------------------------------------------------
$env = (string) config('app.env', 'production');
$isDev = in_array($env, ['local', 'development', 'dev', 'testing'], true);

if ($isDev) {
    // "스케줄러가 실제로 돌아가는지" 확인용 - 운영에서는 불필요
//    Schedule::call(function () {
//        Log::info('[schedule-dev] alive '.now());
//    })
//        ->everyMinute()
//        ->name('dev_scheduler_alive')
//        ->withoutOverlapping();
//
//    // 예시: 5분마다 실행
//    registerScheduleCron('every_5m_log', '*/5 * * * *', function () {
//        Log::info('[job-dev] every 5 minutes '.now());
//    });
//
//    // 예시: 매일 새벽 2시 10분
//    registerScheduleCron('every_day_0210_log', '10 2 * * *', function () {
//        Log::info('[job-dev] daily 02:10 '.now());
//    });
//
//    // 예시: 매월 1일 03:30
//    registerScheduleCron('monthly_1st_0330', '30 3 1 * *', function () {
//        Log::info('[job-dev] monthly 1st 03:30 '.now());
//    });
}


// -----------------------------------------------------------------------------
// 운영용 스케줄은 여기 아래에 "명시적으로" 추가해라.
// - 개발 예시와 섞으면 운영에서 실수할 가능성이 커짐.
// - registerScheduleCron()으로 이름 통일해서 관리.
// -----------------------------------------------------------------------------

// 예시(운영): 정산 배치
// registerScheduleCron('settlement_daily', '0 4 * * *', 'app:settlement:daily', [
//     'without_overlapping' => true,
//     'on_one_server' => true,
// ]);

