<?php

namespace App\Http\Controllers\DevTools;

use App\Http\Controllers\Controller;
use App\Services\ApiExplorer\ApiExplorerService;
use App\Services\ApiExplorer\ApiRequestService;
use App\Services\ApiExplorer\ApiUsageService;
use App\Services\ApiExplorer\OpenApiParserService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;

/**
 * API Explorer Controller
 */
class ApiExplorerController extends Controller
{
    public function __construct(
        private OpenApiParserService $parser,
        private ApiRequestService $requester,
        private ApiExplorerService $explorer,
        private ApiUsageService $usageService
    ) {}

    /*
    |--------------------------------------------------------------------------
    | Main Pages
    |--------------------------------------------------------------------------
    */

    /**
     * 메인 페이지
     */
    public function index(Request $request): View|Response
    {
        // HTMX 요청 시 전체 페이지 리로드 (스크립트 로딩을 위해)
        if ($request->header('HX-Request')) {
            return response('', 200)->header('HX-Redirect', route('dev-tools.api-explorer.index'));
        }

        $userId = auth()->id();

        // 기본 환경 초기화
        $this->explorer->initializeDefaultEnvironments($userId);

        $endpoints = $this->parser->getEndpointsByTag();
        $tags = $this->parser->getTags();
        $bookmarks = $this->explorer->getBookmarks($userId);
        $environments = $this->explorer->getEnvironments($userId);
        $defaultEnv = $this->explorer->getDefaultEnvironment($userId);

        // 세션에 저장된 토큰
        $savedToken = session('api_explorer_token');

        return view('dev-tools.api-explorer.index', compact(
            'endpoints',
            'tags',
            'bookmarks',
            'environments',
            'defaultEnv',
            'savedToken'
        ));
    }

    /*
    |--------------------------------------------------------------------------
    | Endpoint Operations (HTMX partial)
    |--------------------------------------------------------------------------
    */

    /**
     * 엔드포인트 목록 (필터/검색)
     */
    public function endpoints(Request $request): View
    {
        $filters = [
            'search' => $request->input('search'),
            'methods' => $request->input('methods', []),
            'tags' => $request->input('tags', []),
        ];

        $endpoints = $this->parser->filter($filters);
        $endpointsByTag = $endpoints->groupBy(fn ($e) => $e['tags'][0] ?? '기타');
        $bookmarks = $this->explorer->getBookmarks(auth()->id());

        return view('dev-tools.api-explorer.partials.sidebar', compact(
            'endpointsByTag',
            'bookmarks'
        ));
    }

    /**
     * 단일 엔드포인트 상세 (요청 패널)
     */
    public function endpoint(string $operationId): View
    {
        $endpoint = $this->parser->getEndpoint($operationId);

        if (! $endpoint) {
            abort(404, '엔드포인트를 찾을 수 없습니다.');
        }

        $userId = auth()->id();
        $isBookmarked = $this->explorer->isBookmarked($userId, $endpoint['path'], $endpoint['method']);
        $templates = $this->explorer->getTemplates($userId, $endpoint['path'], $endpoint['method']);

        return view('dev-tools.api-explorer.partials.request-panel', compact(
            'endpoint',
            'isBookmarked',
            'templates'
        ));
    }

    /*
    |--------------------------------------------------------------------------
    | API Execution
    |--------------------------------------------------------------------------
    */

    /**
     * API 실행 (프록시)
     */
    public function execute(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'method' => 'required|string|in:GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS',
            'url' => 'required|url',
            'headers' => 'nullable|array',
            'query' => 'nullable|array',
            'body' => 'nullable|array',
            'environment' => 'required|string',
            'token' => 'nullable|string',
            'user_id' => 'nullable|integer',
        ]);

        // Bearer 토큰 처리
        $token = null;
        $headers = $validated['headers'] ?? [];

        // 1. 직접 입력된 토큰
        if (! empty($validated['token'])) {
            $token = $validated['token'];
            session(['api_explorer_token' => $token]);
        }
        // 2. 사용자 선택 시 Sanctum 토큰 발급
        elseif (! empty($validated['user_id'])) {
            $user = \App\Models\User::find($validated['user_id']);
            if ($user) {
                $token = $user->createToken('api-explorer', ['*'])->plainTextToken;
                session(['api_explorer_token' => $token]);
            }
        }
        // 3. 세션에 저장된 토큰 재사용
        elseif (session('api_explorer_token')) {
            $token = session('api_explorer_token');
        }

        // Authorization 헤더 추가 (사용자 입력 토큰이 우선)
        if ($token) {
            $headers['Authorization'] = 'Bearer '.$token;
        }

        // API 실행
        $result = $this->requester->execute(
            $validated['method'],
            $validated['url'],
            $headers,
            $validated['query'] ?? [],
            $validated['body']
        );

        // 히스토리 저장
        $parsedUrl = parse_url($validated['url']);
        $endpoint = $parsedUrl['path'] ?? '/';

        $this->explorer->logRequest(auth()->id(), [
            'endpoint' => $endpoint,
            'method' => $validated['method'],
            'request_headers' => $this->requester->maskSensitiveHeaders($validated['headers'] ?? []),
            'request_body' => $validated['body'],
            'response_status' => $result['status'],
            'response_headers' => $result['headers'],
            'response_body' => is_string($result['body']) ? $result['body'] : json_encode($result['body']),
            'duration_ms' => $result['duration_ms'],
            'environment' => $validated['environment'],
        ]);

        return response()->json($result);
    }

    /*
    |--------------------------------------------------------------------------
    | Bookmarks
    |--------------------------------------------------------------------------
    */

    /**
     * 즐겨찾기 목록
     */
    public function bookmarks(): View
    {
        $bookmarks = $this->explorer->getBookmarks(auth()->id());

        return view('dev-tools.api-explorer.partials.bookmarks', compact('bookmarks'));
    }

    /**
     * 즐겨찾기 저장
     */
    public function storeBookmark(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'endpoint' => 'required|string|max:500',
            'method' => 'required|string|max:10',
            'display_name' => 'nullable|string|max:100',
        ]);

        $bookmark = $this->explorer->addBookmark(auth()->id(), $validated);

        return response()->json([
            'success' => true,
            'bookmark' => $bookmark,
        ]);
    }

    /**
     * 즐겨찾기 토글
     */
    public function toggleBookmark(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'endpoint' => 'required|string|max:500',
            'method' => 'required|string|max:10',
            'display_name' => 'nullable|string|max:100',
        ]);

        $result = $this->explorer->toggleBookmark(auth()->id(), $validated);

        return response()->json($result);
    }

    /**
     * 즐겨찾기 제거
     */
    public function removeBookmark(int $id): JsonResponse
    {
        $this->explorer->removeBookmark($id);

        return response()->json(['success' => true]);
    }

    /**
     * 즐겨찾기 순서 변경
     */
    public function reorderBookmarks(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'order' => 'required|array',
            'order.*' => 'integer',
        ]);

        $this->explorer->reorderBookmarks(auth()->id(), $validated['order']);

        return response()->json(['success' => true]);
    }

    /*
    |--------------------------------------------------------------------------
    | Templates
    |--------------------------------------------------------------------------
    */

    /**
     * 템플릿 목록
     */
    public function templates(Request $request): JsonResponse
    {
        $endpoint = $request->input('endpoint');
        $method = $request->input('method');

        $templates = $this->explorer->getTemplates(auth()->id(), $endpoint, $method);

        return response()->json($templates);
    }

    /**
     * 특정 엔드포인트의 템플릿 목록
     */
    public function templatesForEndpoint(string $endpoint): JsonResponse
    {
        $method = request('method');
        $endpoint = urldecode($endpoint);

        $templates = $this->explorer->getTemplates(auth()->id(), $endpoint, $method);

        return response()->json($templates);
    }

    /**
     * 템플릿 저장
     */
    public function saveTemplate(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'endpoint' => 'required|string|max:500',
            'method' => 'required|string|max:10',
            'name' => 'required|string|max:100',
            'description' => 'nullable|string',
            'headers' => 'nullable|array',
            'path_params' => 'nullable|array',
            'query_params' => 'nullable|array',
            'body' => 'nullable|array',
            'is_shared' => 'nullable|boolean',
        ]);

        $template = $this->explorer->saveTemplate(auth()->id(), $validated);

        return response()->json([
            'success' => true,
            'template' => $template,
        ]);
    }

    /**
     * 템플릿 삭제
     */
    public function deleteTemplate(int $id): JsonResponse
    {
        $this->explorer->deleteTemplate($id);

        return response()->json(['success' => true]);
    }

    /*
    |--------------------------------------------------------------------------
    | History
    |--------------------------------------------------------------------------
    */

    /**
     * 히스토리 목록
     */
    public function history(Request $request): View
    {
        $limit = $request->input('limit', 50);
        $histories = $this->explorer->getHistory(auth()->id(), $limit);

        return view('dev-tools.api-explorer.partials.history-drawer', compact('histories'));
    }

    /**
     * 히스토리 전체 삭제
     */
    public function clearHistory(): JsonResponse
    {
        $count = $this->explorer->clearHistory(auth()->id());

        return response()->json([
            'success' => true,
            'deleted' => $count,
        ]);
    }

    /**
     * 히스토리 재실행
     */
    public function replayHistory(int $id): JsonResponse
    {
        $history = $this->explorer->getHistoryItem($id);

        if (! $history) {
            return response()->json(['error' => '히스토리를 찾을 수 없습니다.'], 404);
        }

        return response()->json([
            'endpoint' => $history->endpoint,
            'method' => $history->method,
            'headers' => $history->request_headers,
            'body' => $history->request_body,
        ]);
    }

    /*
    |--------------------------------------------------------------------------
    | Environments
    |--------------------------------------------------------------------------
    */

    /**
     * 환경 목록
     */
    public function environments(): JsonResponse
    {
        $environments = $this->explorer->getEnvironments(auth()->id());

        return response()->json($environments);
    }

    /**
     * 환경 저장
     */
    public function saveEnvironment(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'id' => 'nullable|integer',
            'name' => 'required|string|max:50',
            'base_url' => 'required|url|max:500',
            'api_key' => 'nullable|string|max:500',
            'auth_token' => 'nullable|string',
            'variables' => 'nullable|array',
            'is_default' => 'nullable|boolean',
        ]);

        if (! empty($validated['id'])) {
            $environment = $this->explorer->updateEnvironment($validated['id'], $validated);
        } else {
            $environment = $this->explorer->saveEnvironment(auth()->id(), $validated);
        }

        return response()->json([
            'success' => true,
            'environment' => $environment,
        ]);
    }

    /**
     * 환경 삭제
     */
    public function deleteEnvironment(int $id): JsonResponse
    {
        $this->explorer->deleteEnvironment($id);

        return response()->json(['success' => true]);
    }

    /**
     * 기본 환경 설정
     */
    public function setDefaultEnvironment(int $id): JsonResponse
    {
        $this->explorer->setDefaultEnvironment(auth()->id(), $id);

        return response()->json(['success' => true]);
    }

    /*
    |--------------------------------------------------------------------------
    | Users (for Authentication)
    |--------------------------------------------------------------------------
    */

    /**
     * 현재 테넌트의 사용자 목록
     * 시스템 헤더에서 선택한 테넌트 기준 (session('selected_tenant_id'))
     * 관리자는 자신이 속하지 않은 테넌트의 사용자도 볼 수 있어야 함
     */
    public function users(): JsonResponse
    {
        // 세션에서 직접 테넌트 ID 조회 (관리자가 선택한 테넌트)
        $selectedTenantId = session('selected_tenant_id');

        if (! $selectedTenantId) {
            // 테넌트가 선택되지 않은 경우 로그인 사용자의 기본 테넌트 사용
            $currentTenant = auth()->user()->tenants()
                ->where('is_default', true)
                ->first() ?? auth()->user()->tenants()->first();

            if (! $currentTenant) {
                return response()->json([]);
            }

            $selectedTenantId = $currentTenant->id;
        }

        // Tenant 모델에서 직접 조회 (사용자의 테넌트 관계와 무관하게)
        $tenant = \App\Models\Tenants\Tenant::find($selectedTenantId);

        if (! $tenant) {
            return response()->json([]);
        }

        // 해당 테넌트에 속한 사용자 목록 조회
        $users = \App\Models\User::whereHas('tenants', function ($query) use ($selectedTenantId) {
            $query->where('tenant_id', $selectedTenantId);
        })
            ->select(['id', 'name', 'email'])
            ->orderBy('name')
            ->limit(100)
            ->get();

        return response()->json([
            'tenant' => [
                'id' => $tenant->id,
                'name' => $tenant->company_name,
            ],
            'users' => $users,
        ]);
    }

    /**
     * 사용자 선택 시 Sanctum 토큰 발급
     */
    public function issueToken(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'user_id' => 'required|integer|exists:users,id',
        ]);

        $user = \App\Models\User::find($validated['user_id']);

        if (! $user) {
            return response()->json(['error' => '사용자를 찾을 수 없습니다.'], 404);
        }

        // Sanctum 토큰 발급
        $token = $user->createToken('api-explorer', ['*'])->plainTextToken;
        session(['api_explorer_token' => $token]);

        return response()->json([
            'success' => true,
            'token' => $token,
            'user' => [
                'id' => $user->id,
                'name' => $user->name,
                'email' => $user->email,
            ],
        ]);
    }

    /**
     * 즐겨찾기 수정
     */
    public function updateBookmark(Request $request, int $id): JsonResponse
    {
        $validated = $request->validate([
            'display_name' => 'nullable|string|max:100',
        ]);

        $bookmark = $this->explorer->updateBookmark($id, $validated);

        return response()->json([
            'success' => true,
            'bookmark' => $bookmark,
        ]);
    }

    /**
     * 즐겨찾기 삭제
     */
    public function deleteBookmark(int $id): JsonResponse
    {
        $this->explorer->removeBookmark($id);

        return response()->json(['success' => true]);
    }

    /*
    |--------------------------------------------------------------------------
    | API Usage & Deprecation
    |--------------------------------------------------------------------------
    */

    /**
     * API 사용 현황 페이지
     */
    public function usage(Request $request): View|Response
    {
        // HTMX 요청 시 전체 페이지 리로드
        if ($request->header('HX-Request')) {
            return response('', 200)->header('HX-Redirect', route('dev-tools.api-explorer.usage'));
        }

        $comparison = $this->usageService->getApiUsageComparison();
        $deprecations = $this->usageService->getDeprecations();
        $dailyTrend = $this->usageService->getDailyTrend(30);

        return view('dev-tools.api-explorer.usage', compact(
            'comparison',
            'deprecations',
            'dailyTrend'
        ));
    }

    /**
     * API 사용 통계 조회 (JSON)
     */
    public function usageStats(): JsonResponse
    {
        $comparison = $this->usageService->getApiUsageComparison();

        return response()->json($comparison);
    }

    /**
     * 폐기 후보 목록 조회
     */
    public function deprecations(Request $request): JsonResponse
    {
        $status = $request->input('status');
        $deprecations = $this->usageService->getDeprecations($status);

        return response()->json($deprecations);
    }

    /**
     * 폐기 후보 추가
     */
    public function addDeprecation(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'endpoint' => 'required|string|max:500',
            'method' => 'required|string|max:10',
            'reason' => 'nullable|string',
        ]);

        $deprecation = $this->usageService->addDeprecationCandidate(
            $validated['endpoint'],
            $validated['method'],
            $validated['reason'] ?? null,
            auth()->id()
        );

        return response()->json([
            'success' => true,
            'deprecation' => $deprecation,
        ]);
    }

    /**
     * 미사용 API 전체를 폐기 후보로 추가
     */
    public function addAllUnusedAsDeprecation(): JsonResponse
    {
        $count = $this->usageService->addAllUnusedAsCandidate(auth()->id());

        return response()->json([
            'success' => true,
            'added_count' => $count,
        ]);
    }

    /**
     * 폐기 상태 변경
     */
    public function updateDeprecation(Request $request, int $id): JsonResponse
    {
        $validated = $request->validate([
            'status' => 'required|string|in:candidate,scheduled,deprecated,removed',
            'reason' => 'nullable|string',
            'scheduled_date' => 'nullable|date',
        ]);

        $scheduledDate = ! empty($validated['scheduled_date'])
            ? new \DateTime($validated['scheduled_date'])
            : null;

        $deprecation = $this->usageService->updateDeprecationStatus(
            $id,
            $validated['status'],
            $validated['reason'] ?? null,
            $scheduledDate
        );

        return response()->json([
            'success' => true,
            'deprecation' => $deprecation,
        ]);
    }

    /**
     * 폐기 후보 삭제
     */
    public function removeDeprecation(int $id): JsonResponse
    {
        $this->usageService->removeDeprecation($id);

        return response()->json(['success' => true]);
    }

    /**
     * 일별 API 호출 추이
     */
    public function dailyTrend(Request $request): JsonResponse
    {
        $days = $request->input('days', 30);
        $trend = $this->usageService->getDailyTrend($days);

        return response()->json($trend);
    }

    /**
     * 인기 API 목록
     */
    public function popularApis(Request $request): JsonResponse
    {
        $limit = $request->input('limit', 20);
        $popular = $this->usageService->getPopularApis($limit);

        return response()->json($popular);
    }

    /**
     * 오래된 API 목록 (N일 이상 미사용)
     */
    public function staleApis(Request $request): JsonResponse
    {
        $days = $request->input('days', 30);
        $stale = $this->usageService->getStaleApis($days);

        return response()->json($stale);
    }
}
