<?php

namespace App\Http\Controllers\DevTools;

use App\Http\Controllers\Controller;
use App\Models\Admin\AdminApiFlow;
use App\Models\Admin\AdminApiFlowRun;
use App\Services\FlowTester\FlowExecutor;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;

/**
 * API Flow Tester Controller
 *
 * API 플로우 테스트 도구 컨트롤러
 */
class FlowTesterController extends Controller
{
    /**
     * 플로우 목록
     */
    public function index(Request $request): View|Response
    {
        // HTMX 요청 시 전체 페이지 리로드 (스크립트 로딩을 위해)
        if ($request->header('HX-Request')) {
            return response('', 200)->header('HX-Redirect', route('dev-tools.flow-tester.index'));
        }

        $flows = AdminApiFlow::with('latestRun')
            ->orderByDesc('created_at')
            ->paginate(20);

        // 세션에 저장된 토큰 (API Explorer와 공유)
        $savedToken = session('api_explorer_token');
        $selectedUserId = session('api_explorer_user_id');
        $selectedUser = $selectedUserId ? \App\Models\User::find($selectedUserId) : null;

        return view('dev-tools.flow-tester.index', compact('flows', 'savedToken', 'selectedUser'));
    }

    /**
     * 플로우 생성 폼
     */
    public function create(Request $request): View|Response
    {
        // HTMX 요청 시 전체 페이지 리로드
        if ($request->header('HX-Request')) {
            return response('', 200)->header('HX-Redirect', route('dev-tools.flow-tester.create'));
        }

        return view('dev-tools.flow-tester.create');
    }

    /**
     * 플로우 저장
     */
    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:100',
            'description' => 'nullable|string',
            'category' => 'nullable|string|max:50',
            'flow_definition' => 'required|json',
        ]);

        $validated['flow_definition'] = json_decode($validated['flow_definition'], true);
        $validated['created_by'] = auth()->id();

        $flow = AdminApiFlow::create($validated);

        return redirect()
            ->route('dev-tools.flow-tester.edit', $flow->id)
            ->with('success', '플로우가 생성되었습니다.');
    }

    /**
     * 플로우 편집 폼
     */
    public function edit(Request $request, int $id): View|Response
    {
        // HTMX 요청 시 전체 페이지 리로드
        if ($request->header('HX-Request')) {
            return response('', 200)->header('HX-Redirect', route('dev-tools.flow-tester.edit', $id));
        }

        $flow = AdminApiFlow::findOrFail($id);

        return view('dev-tools.flow-tester.edit', compact('flow'));
    }

    /**
     * 플로우 수정
     */
    public function update(Request $request, int $id)
    {
        $flow = AdminApiFlow::findOrFail($id);

        $validated = $request->validate([
            'name' => 'required|string|max:100',
            'description' => 'nullable|string',
            'category' => 'nullable|string|max:50',
            'flow_definition' => 'required|json',
            'is_active' => 'boolean',
        ]);

        $validated['flow_definition'] = json_decode($validated['flow_definition'], true);
        $validated['updated_by'] = auth()->id();

        $flow->update($validated);

        return redirect()
            ->route('dev-tools.flow-tester.edit', $flow->id)
            ->with('success', '플로우가 수정되었습니다.');
    }

    /**
     * 플로우 삭제
     */
    public function destroy(int $id)
    {
        $flow = AdminApiFlow::findOrFail($id);
        $flow->delete();

        // AJAX 요청인 경우 JSON 응답 반환
        if (request()->ajax() || request()->wantsJson()) {
            return response()->json([
                'success' => true,
                'message' => '플로우가 삭제되었습니다.',
            ]);
        }

        return redirect()
            ->route('dev-tools.flow-tester.index')
            ->with('success', '플로우가 삭제되었습니다.');
    }

    /**
     * 플로우 복제
     */
    public function clone(int $id)
    {
        $original = AdminApiFlow::findOrFail($id);

        $clone = $original->replicate();
        $clone->name = $original->name.' (복사본)';
        $clone->created_by = auth()->id();
        $clone->updated_by = null;
        $clone->save();

        return redirect()
            ->route('dev-tools.flow-tester.edit', $clone->id)
            ->with('success', '플로우가 복제되었습니다.');
    }

    /**
     * JSON 유효성 검사 및 메타 정보 추출
     */
    public function validateJson(Request $request)
    {
        $json = $request->input('flow_definition', '');

        try {
            $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);

            // 기본 구조 검증
            $errors = [];

            if (! isset($data['steps']) || ! is_array($data['steps'])) {
                $errors[] = 'steps 배열이 필요합니다.';
            } else {
                foreach ($data['steps'] as $i => $step) {
                    if (empty($step['id'])) {
                        $errors[] = "steps[{$i}]: id가 필요합니다.";
                    }
                    if (empty($step['method'])) {
                        $errors[] = "steps[{$i}]: method가 필요합니다.";
                    }
                    if (empty($step['endpoint'])) {
                        $errors[] = "steps[{$i}]: endpoint가 필요합니다.";
                    }
                }
            }

            if (! empty($errors)) {
                return response()->json([
                    'valid' => false,
                    'errors' => $errors,
                ]);
            }

            // meta 정보 추출 (최상위 또는 meta 객체에서)
            $meta = $data['meta'] ?? [];
            $tags = $meta['tags'] ?? [];

            // 카테고리 추론: 최상위 category > tags[0] > endpoint에서 추출 (login 제외)
            $category = $data['category'] ?? $tags[0] ?? null;
            if (! $category && ! empty($data['steps'])) {
                // login, auth, refresh, logout 등 인증 관련 엔드포인트는 건너뛰고 추출
                $authEndpoints = ['/login', '/logout', '/refresh', '/auth'];
                foreach ($data['steps'] as $step) {
                    $endpoint = $step['endpoint'] ?? '';
                    // 인증 엔드포인트가 아닌 첫 번째 스텝에서 카테고리 추출
                    if (! in_array($endpoint, $authEndpoints) && preg_match('#^/([^/]+)#', $endpoint, $matches)) {
                        $category = $matches[1];
                        break;
                    }
                }
            }

            // 이름 추론: 최상위 name > meta.name > description 첫 부분
            $name = $data['name'] ?? $meta['name'] ?? null;
            if (! $name) {
                $description = $data['description'] ?? $meta['description'] ?? null;
                if ($description) {
                    // 설명의 첫 번째 줄 또는 50자까지
                    $name = mb_substr(strtok($description, "\n"), 0, 50);
                }
            }

            // 설명 추론: 최상위 description > meta.description
            $description = $data['description'] ?? $meta['description'] ?? null;

            return response()->json([
                'valid' => true,
                'stepCount' => count($data['steps'] ?? []),
                'extracted' => [
                    'name' => $name,
                    'description' => $description,
                    'category' => $category,
                    'author' => $meta['author'] ?? null,
                    'tags' => $tags,
                    'version' => $data['version'] ?? '1.0',
                ],
            ]);
        } catch (\JsonException $e) {
            return response()->json([
                'valid' => false,
                'errors' => ['JSON 파싱 오류: '.$e->getMessage()],
            ]);
        }
    }

    /**
     * 플로우 실행
     */
    public function run(int $id)
    {
        $flow = AdminApiFlow::findOrFail($id);

        // 실행 기록 생성
        $run = AdminApiFlowRun::create([
            'flow_id' => $flow->id,
            'status' => AdminApiFlowRun::STATUS_RUNNING,
            'started_at' => now(),
            'total_steps' => $flow->step_count,
            'executed_by' => auth()->id(),
        ]);

        try {
            // FlowExecutor로 실제 실행
            $executor = new FlowExecutor;
            $result = $executor->execute($flow->flow_definition);

            // 실행 결과 저장
            $run->update([
                'status' => $result['status'],
                'completed_at' => now(),
                'duration_ms' => $result['duration'],
                'completed_steps' => $result['completedSteps'],
                'failed_step' => $result['failedStep'],
                'execution_log' => $result['executionLog'],
                'error_message' => $result['errorMessage'],
                'api_logs' => $result['apiLogs'] ?? [],
            ]);

            return response()->json([
                'success' => $result['status'] === 'SUCCESS',
                'run_id' => $run->id,
                'status' => $result['status'],
                'message' => $this->getResultMessage($result),
                'result' => $result,
            ]);
        } catch (\Exception $e) {
            // 예외 발생 시 실패 처리
            $run->update([
                'status' => AdminApiFlowRun::STATUS_FAILED,
                'completed_at' => now(),
                'error_message' => $e->getMessage(),
            ]);

            return response()->json([
                'success' => false,
                'run_id' => $run->id,
                'status' => 'FAILED',
                'message' => '실행 오류: '.$e->getMessage(),
            ], 500);
        }
    }

    /**
     * 실행 결과 메시지 생성
     */
    private function getResultMessage(array $result): string
    {
        return match ($result['status']) {
            'SUCCESS' => "플로우 실행 완료! ({$result['completedSteps']}/{$result['totalSteps']} 스텝 성공)",
            'FAILED' => '플로우 실행 실패: '.($result['errorMessage'] ?? '알 수 없는 오류'),
            'PARTIAL' => "부분 성공: {$result['completedSteps']}/{$result['totalSteps']} 스텝 완료",
            default => "실행 완료 (상태: {$result['status']})",
        };
    }

    /**
     * 실행 상태 조회 (Polling)
     */
    public function runStatus(int $runId)
    {
        $run = AdminApiFlowRun::findOrFail($runId);

        return response()->json([
            'status' => $run->status,
            'progress' => $run->progress,
            'completed_steps' => $run->completed_steps,
            'total_steps' => $run->total_steps,
            'is_completed' => $run->isCompleted(),
            'execution_log' => $run->execution_log,
        ]);
    }

    /**
     * 실행 이력 목록
     */
    public function history(Request $request, int $id): View|Response
    {
        // HTMX 요청 시 전체 페이지 리로드
        if ($request->header('HX-Request')) {
            return response('', 200)->header('HX-Redirect', route('dev-tools.flow-tester.history', $id));
        }

        $flow = AdminApiFlow::findOrFail($id);
        $runs = $flow->runs()
            ->orderByDesc('created_at')
            ->paginate(20);

        return view('dev-tools.flow-tester.history', compact('flow', 'runs'));
    }

    /**
     * 실행 상세 보기
     */
    public function runDetail(Request $request, int $runId): View|Response
    {
        // HTMX 요청 시 전체 페이지 리로드
        if ($request->header('HX-Request')) {
            return response('', 200)->header('HX-Redirect', route('dev-tools.flow-tester.run-detail', $runId));
        }

        $run = AdminApiFlowRun::with('flow')->findOrFail($runId);

        return view('dev-tools.flow-tester.run-detail', compact('run'));
    }

    /*
    |--------------------------------------------------------------------------
    | Token & User Management (API Explorer와 공유)
    |--------------------------------------------------------------------------
    */

    /**
     * API 서버에 직접 로그인하여 토큰 발급
     *
     * MNG에서 토큰을 발급하면 API 서버에서 인식하지 못하므로,
     * API 서버에 직접 로그인하여 토큰을 발급받습니다.
     */
    public function loginToApi(Request $request)
    {
        $validated = $request->validate([
            'user_id' => 'required|string',
            'user_pwd' => 'required|string',
        ]);

        try {
            // API Base URL 결정
            $baseUrl = $this->getApiBaseUrl();

            // Docker 환경에서는 내부 URL로 변환
            $requestUrl = $baseUrl.'/login';
            $headers = ['Accept' => 'application/json', 'Content-Type' => 'application/json'];

            if ($this->isDockerEnvironment()) {
                $parsedUrl = parse_url($baseUrl);
                $host = $parsedUrl['host'] ?? '';

                // *.sam.kr 도메인을 nginx 컨테이너로 라우팅
                if (str_ends_with($host, '.sam.kr') || $host === 'sam.kr') {
                    $headers['Host'] = $host;
                    $requestUrl = preg_replace('#https?://[^/]+#', 'https://nginx', $baseUrl).'/login';
                }
            }

            // API 서버에 로그인 요청
            $response = \Illuminate\Support\Facades\Http::withHeaders($headers)
                ->withoutVerifying() // Docker 내부 SSL 인증서 무시
                ->timeout(10)
                ->post($requestUrl, [
                    'user_id' => $validated['user_id'],
                    'user_pwd' => $validated['user_pwd'],
                ]);

            if (! $response->successful()) {
                $body = $response->json();

                return response()->json([
                    'success' => false,
                    'message' => $body['message'] ?? '로그인 실패: '.$response->status(),
                ], 401);
            }

            $body = $response->json();
            $token = $body['access_token'] ?? $body['data']['token'] ?? null;

            if (! $token) {
                return response()->json([
                    'success' => false,
                    'message' => '토큰을 받지 못했습니다. 응답: '.json_encode($body, JSON_UNESCAPED_UNICODE),
                ], 500);
            }

            // 세션에 저장 (API Explorer와 공유)
            session([
                'api_explorer_token' => $token,
                'api_explorer_user_id' => $body['user']['id'] ?? null,
                'api_explorer_user_name' => $body['user']['name'] ?? $validated['user_id'],
            ]);

            return response()->json([
                'success' => true,
                'message' => 'API 서버 로그인 성공!',
                'user' => $body['user'] ?? ['name' => $validated['user_id']],
                'token_preview' => substr($token, 0, 20).'...',
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'API 서버 연결 실패: '.$e->getMessage(),
            ], 500);
        }
    }

    /**
     * API Base URL 결정
     */
    private function getApiBaseUrl(): string
    {
        // 환경변수 우선
        $envUrl = env('FLOW_TESTER_API_BASE_URL');
        if ($envUrl) {
            return rtrim($envUrl, '/');
        }

        // config에서 로컬 환경 URL
        $environments = config('api-explorer.default_environments', []);
        foreach ($environments as $env) {
            if ($env['name'] === '로컬') {
                return rtrim($env['base_url'], '/');
            }
        }

        // 기본값
        return 'https://api.sam.kr';
    }

    /**
     * Docker 환경인지 확인
     */
    private function isDockerEnvironment(): bool
    {
        return file_exists('/.dockerenv') || (getenv('DOCKER_CONTAINER') === 'true');
    }

    /**
     * Bearer 토큰 저장 (직접 입력)
     */
    public function saveToken(Request $request)
    {
        $validated = $request->validate([
            'token' => 'required|string',
        ]);

        // API Explorer와 같은 세션 키 사용
        session([
            'api_explorer_token' => $validated['token'],
            'api_explorer_user_id' => null, // 직접 입력 시 사용자 정보 없음
        ]);

        return response()->json([
            'success' => true,
            'message' => '토큰이 저장되었습니다.',
        ]);
    }

    /**
     * Bearer 토큰 초기화
     */
    public function clearToken()
    {
        session()->forget(['api_explorer_token', 'api_explorer_user_id']);

        return response()->json([
            'success' => true,
            'message' => '인증이 초기화되었습니다.',
        ]);
    }

    /**
     * 현재 토큰 상태 조회
     */
    public function tokenStatus()
    {
        $token = session('api_explorer_token');
        $userId = session('api_explorer_user_id');
        $user = $userId ? \App\Models\User::find($userId) : null;

        return response()->json([
            'has_token' => ! empty($token),
            'token_preview' => $token ? substr($token, 0, 20).'...' : null,
            'user' => $user ? [
                'id' => $user->id,
                'name' => $user->name,
                'email' => $user->email,
            ] : null,
        ]);
    }
}
