<?php

namespace App\Commands;

use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;

use App\Models\Entities\NaverWorkerLogModel; // 새로 만든 테이블용 모델

// 헬퍼 로드 (app/Helpers/log_helper.php 가 있어야 함 autoload 설정 넣어놓았음)

class NaverWorker extends BaseCommand
{
    protected $group       = 'Workers';
    protected $name        = 'naver:worker';
    protected $description = 'Redis에서 데이터를 꺼내 DB에 저장하고 네이버 API를 호출합니다.';

    // DB 객체를 담을 변수 선언
    protected $db;
    protected $redisHost;
    protected $redisPort;
    protected $redisDatabase;

    public function run(array $params)
    {
        helper('log'); // 여기서 로드 완료!
        
        $this->db = \Config\Database::connect();
        $logModel = model(NaverWorkerLogModel::class);
        $naverService = new \App\Services\NaverService(); // 서비스 생성

        $redis = new \Redis();
        try {
            // 두 가지 환경 변수 형식 지원 (REDIS_HOST 또는 redis.default.host)
            $this->redisHost = getenv('REDIS_HOST') ?: (getenv('redis.default.host') ?: '127.0.0.1');
            $this->redisPort = getenv('REDIS_PORT') ?: (getenv('redis.default.port') ?: 6379);
            $this->redisDatabase = getenv('REDIS_DATABASE') ?: (getenv('redis.default.database') ?: 9);
            
            $redis->connect($this->redisHost, (int)$this->redisPort);
            $redis->select((int)$this->redisDatabase);
            CLI::write(CLI::color('🟢 Naver Worker running... (Redis: ' . $this->redisHost . ':' . $this->redisPort . ' DB:' . $this->redisDatabase . ')', 'green'));
        } catch (\Exception $e) {
            CLI::error("Redis 연결 불가: " . $e->getMessage());
            return;
        }

        

    while (true) {

        // Redis brPop with retry logic
        $maxRetries = 3;
        $retryCount = 0;
        $result = null;
        
        while ($retryCount < $maxRetries) {
            try {
                $result = $redis->brPop(['naver:raw_queue'], 30);
                break; // 성공하면 루프 탈출
            } catch (\RedisException $e) {
                $retryCount++;
                CLI::write(CLI::color("⚠️  Redis error (attempt {$retryCount}/{$maxRetries}): " . $e->getMessage(), 'yellow'));
                
                if ($retryCount >= $maxRetries) {
                    CLI::error("❌ Redis reconnection failed after {$maxRetries} attempts");
                    break;
                }
                
                // Redis 재연결 시도
                try {
                    CLI::write(CLI::color('🔄 Reconnecting to Redis...', 'yellow'));
                    $redis->close();
                    $redis->connect($this->redisHost, (int)$this->redisPort);
                    $redis->select((int)$this->redisDatabase);
                    CLI::write(CLI::color('✅ Redis reconnected', 'green'));
                } catch (\Exception $reconnectError) {
                    CLI::error("Redis reconnection error: " . $reconnectError->getMessage());
                    sleep(2); // 재연결 실패 시 잠시 대기
                }
            }
        }

        if (!$result) {
            // 데이터가 없어서 타임아웃 난 경우. 
            // 굳이 sleep 안 해도 바로 다음 brPop이 다시 30초 대기를 시작함.
            continue;
        }

        if ($result) {
                $rawData = $result[1];
                
                // [1] 꺼내자마자 DB에 원문 저장 (2차 임시 저장) - 실패 시 재시도
                try {
                    $logId = $logModel->insert([
                        'raw_payload' => $rawData,
                        'status'      => 'INIT'
                    ]);
                } catch (\CodeIgniter\Database\Exceptions\DatabaseException $e) {
                    // MySQL gone away 에러 시 재연결 후 재시도
                    if (strpos($e->getMessage(), 'MySQL server has gone away') !== false) {
                        CLI::write(CLI::color('⚠️  MySQL gone away, reconnecting...', 'yellow'));
                        $this->db->close();
                        $this->db = \Config\Database::connect();
                        $logModel = model(NaverWorkerLogModel::class);
                        
                        // 재시도
                        $logId = $logModel->insert([
                            'raw_payload' => $rawData,
                            'status'      => 'INIT'
                        ]);
                    } else {
                        throw $e; // 다른 에러면 그대로 throw
                    }
                }

            try {
                $responseJson = json_decode($result[1], true);
                $payload = $responseJson['request_data'] ?? [];

                if (empty($payload)) {
                    throw new \Exception("빈 페이로드 데이터");
                }

                // 서비스의 함수 하나로 모든 처리 완료
                $insertId = $naverService->processArticle($payload);

                // [3] 성공 시 로그 업데이트 (재연결 처리 포함)
                $this->safeUpdateLog($logModel, $logId, [
                    'atcl_no' => $payload['articleNumber'] ?? null,
                    'status'  => 'SUCCESS',
                    'target_db_id' => $insertId
                ]);
                
                CLI::write("✅ Success! DB ID: $insertId", 'cyan');

            } catch (\Exception $e) {
                CLI::error("❌ Task Failed: " . $e->getMessage());
                // 실패 로그는 여기서 남김
                // 1. DB 상태를 FAIL로 업데이트 (필수) (재연결 처리 포함)
                $this->safeUpdateLog($logModel, $logId, [
                    'status' => 'FAIL', 
                    'error_msg' => $e->getMessage()
                ]);

                // 2. Redis 실패 큐에 백업 (선택 - 나중에 모아서 다시 던질 때 편함)
                $redis->lPush('naver:failed_queue', $rawData);
                helper('log');
                write_custom_log("FAILED_DATA | Error: " . $e->getMessage(), 'ERROR', 'failed');

                // 루프 과부하 방지 (연속 에러 시)
                sleep(1);
            }
        }
    }
    }

    /**
     * MySQL gone away 에러 발생 시 재연결 후 재시도하는 안전한 update
     */
    protected function safeUpdateLog($logModel, $logId, $data)
    {
        try {
            return $logModel->update($logId, $data);
        } catch (\CodeIgniter\Database\Exceptions\DatabaseException $e) {
            if (strpos($e->getMessage(), 'MySQL server has gone away') !== false) {
                CLI::write(CLI::color('⚠️  MySQL gone away on update, reconnecting...', 'yellow'));
                $this->db->close();
                $this->db = \Config\Database::connect();
                $logModel = model(\App\Models\Entities\NaverWorkerLogModel::class);
                
                // 재시도
                return $logModel->update($logId, $data);
            } else {
                throw $e;
            }
        }
    }

    
}