<?php

namespace App\Services\FlowTester;

/**
 * API 로그 캡처 서비스
 *
 * API 서버의 laravel.log에서 Request/Response 로그를 캡처합니다.
 * 플로우 실행 시작/종료 시점의 파일 오프셋을 이용하여
 * 해당 실행 중에 발생한 로그만 추출합니다.
 */
class ApiLogCapturer
{
    private string $logPath;

    private int $startOffset = 0;

    public function __construct()
    {
        // API 로그 파일 경로 (Docker/로컬 환경 모두 지원)
        $this->logPath = $this->resolveLogPath();
    }

    /**
     * 캡처 시작 (현재 로그 파일 위치 기록)
     */
    public function start(): void
    {
        if (file_exists($this->logPath)) {
            $this->startOffset = filesize($this->logPath);
        } else {
            $this->startOffset = 0;
        }
    }

    /**
     * 캡처 종료 및 로그 추출
     *
     * @return array 파싱된 API 로그 배열
     */
    public function capture(): array
    {
        if (! file_exists($this->logPath)) {
            return [];
        }

        $currentSize = filesize($this->logPath);

        // 새로운 로그가 없으면 빈 배열 반환
        if ($currentSize <= $this->startOffset) {
            return [];
        }

        // 새로 추가된 로그 읽기
        $handle = fopen($this->logPath, 'r');
        if (! $handle) {
            return [];
        }

        fseek($handle, $this->startOffset);
        $newLogs = fread($handle, $currentSize - $this->startOffset);
        fclose($handle);

        // Request/Response 로그만 파싱
        return $this->parseLogs($newLogs);
    }

    /**
     * API 로그 파일 경로 결정
     */
    private function resolveLogPath(): string
    {
        // 1. 환경 변수로 지정된 경로
        $envPath = env('API_LOG_PATH');
        if ($envPath && file_exists($envPath)) {
            return $envPath;
        }

        // 2. 로컬 개발 환경 (상대 경로)
        $localPath = base_path('../api/storage/logs/laravel.log');
        if (file_exists($localPath)) {
            return $localPath;
        }

        // 3. Docker 환경 (절대 경로)
        $dockerPath = '/var/www/api/storage/logs/laravel.log';
        if (file_exists($dockerPath)) {
            return $dockerPath;
        }

        // 4. 기본값 (로컬 경로)
        return $localPath;
    }

    /**
     * 로그 텍스트 파싱
     *
     * Laravel 로그 형식:
     * [2025-12-04 12:30:53] local.INFO: API Request {...}
     * [2025-12-04 12:30:53] local.INFO: API Response {...}
     */
    private function parseLogs(string $rawLogs): array
    {
        $logs = [];
        // 전체 로그 라인 매칭 (원본 보존용)
        $pattern = '/(\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] \w+\.\w+: (API Request|API Response) (\{.+?\}))(?=\s*\[\d{4}|\s*$)/s';

        if (preg_match_all($pattern, $rawLogs, $matches, PREG_SET_ORDER)) {
            foreach ($matches as $match) {
                $rawLine = $match[1];  // 전체 원본 로그 라인
                $timestamp = $match[2];
                $type = $match[3] === 'API Request' ? 'request' : 'response';
                $jsonStr = $match[4];

                // JSON 파싱
                $data = json_decode($jsonStr, true);
                if ($data === null) {
                    continue;
                }

                $log = [
                    'timestamp' => $timestamp,
                    'type' => $type,
                    'raw' => $this->decodeUnicodeEscapes($rawLine),  // 유니코드 이스케이프 디코딩
                ];

                if ($type === 'request') {
                    $log['method'] = $data['method'] ?? '';
                    $log['uri'] = $data['uri'] ?? '';
                    $log['input'] = $data['input'] ?? [];
                    $log['ip'] = $data['ip'] ?? '';
                } else {
                    $log['uri'] = $data['uri'] ?? '';
                    $log['status'] = $data['status'] ?? 0;

                    // content는 JSON 문자열이므로 파싱
                    $content = $data['content'] ?? '';
                    if (is_string($content)) {
                        $parsedContent = json_decode($content, true);
                        if ($parsedContent !== null) {
                            $log['success'] = $parsedContent['success'] ?? null;
                            $log['message'] = $parsedContent['message'] ?? '';

                            // 에러 정보가 있으면 포함
                            if (isset($parsedContent['error'])) {
                                $log['error'] = $parsedContent['error'];
                            }
                        }
                    }
                }

                $logs[] = $log;
            }
        }

        return $logs;
    }

    /**
     * 로그 파일 경로 반환 (디버깅용)
     */
    public function getLogPath(): string
    {
        return $this->logPath;
    }

    /**
     * 로그 파일 존재 여부 확인
     */
    public function isAvailable(): bool
    {
        return file_exists($this->logPath) && is_readable($this->logPath);
    }

    /**
     * 유니코드 이스케이프 시퀀스 디코딩
     *
     * JSON 내부의 이중 이스케이프된 유니코드를 실제 문자로 변환
     * 예: \\u0000 또는 \\\\u0000 → 실제 유니코드 문자
     */
    private function decodeUnicodeEscapes(string $str): string
    {
        // 이중 이스케이프 (\\\\uXXXX) 디코딩
        $str = preg_replace_callback('/\\\\\\\\u([0-9a-fA-F]{4})/', function ($match) {
            return json_decode('"\u'.$match[1].'"') ?? $match[0];
        }, $str);

        // 단일 이스케이프 (\\uXXXX) 디코딩
        $str = preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/', function ($match) {
            return json_decode('"\u'.$match[1].'"') ?? $match[0];
        }, $str);

        return $str;
    }
}
