<?php

namespace App\Http\Controllers\System;

use App\Http\Controllers\Controller;
use App\Models\System\AiConfig;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;

class AiConfigController extends Controller
{
    /**
     * AI 설정 목록
     */
    public function index(Request $request): View|Response
    {
        if ($request->header('HX-Request')) {
            return response('', 200)->header('HX-Redirect', route('system.ai-config.index'));
        }

        // AI 설정 (gemini, claude, openai)
        $aiConfigs = AiConfig::whereIn('provider', AiConfig::AI_PROVIDERS)
            ->orderBy('provider')
            ->orderByDesc('is_active')
            ->orderBy('name')
            ->get();

        // 스토리지 설정 (gcs)
        $storageConfigs = AiConfig::whereIn('provider', AiConfig::STORAGE_PROVIDERS)
            ->orderBy('provider')
            ->orderByDesc('is_active')
            ->orderBy('name')
            ->get();

        // API 서비스 설정 (notion)
        $apiServiceConfigs = AiConfig::whereIn('provider', AiConfig::API_SERVICE_PROVIDERS)
            ->orderBy('provider')
            ->orderByDesc('is_active')
            ->orderBy('name')
            ->get();

        return view('system.ai-config.index', [
            'configs' => $aiConfigs,
            'aiConfigs' => $aiConfigs,
            'storageConfigs' => $storageConfigs,
            'apiServiceConfigs' => $apiServiceConfigs,
        ]);
    }

    /**
     * AI 설정 저장
     */
    public function store(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'name' => 'required|string|max:50',
            'provider' => 'required|string|in:gemini,claude,openai,gcs,notion',
            'api_key' => 'nullable|string|max:255',
            'model' => 'nullable|string|max:100',
            'base_url' => 'nullable|string|max:255',
            'description' => 'nullable|string',
            'is_active' => 'boolean',
            'options' => 'nullable|array',
            'options.auth_type' => 'nullable|string|in:api_key,vertex_ai,service_account',
            'options.project_id' => 'nullable|string|max:100',
            'options.region' => 'nullable|string|max:50',
            'options.service_account_path' => 'nullable|string|max:500',
            'options.bucket_name' => 'nullable|string|max:200',
            'options.service_account_json' => 'nullable|array',
        ]);

        // GCS의 경우 별도 검증
        if ($validated['provider'] === 'gcs') {
            if (empty($validated['options']['bucket_name'])) {
                return response()->json([
                    'ok' => false,
                    'message' => '버킷 이름을 입력해주세요.',
                ], 422);
            }
            $validated['model'] = '-'; // GCS는 모델 불필요
            $validated['api_key'] = 'gcs_service_account'; // DB NOT NULL 제약
        } else {
            // AI 설정: Vertex AI가 아닌 경우 API 키 필수
            $authType = $validated['options']['auth_type'] ?? 'api_key';
            if ($authType !== 'vertex_ai' && empty($validated['api_key'])) {
                return response()->json([
                    'ok' => false,
                    'message' => 'API 키를 입력해주세요.',
                ], 422);
            }
        }

        // 활성화 시 동일 provider의 다른 설정 비활성화
        if ($validated['is_active'] ?? false) {
            AiConfig::where('provider', $validated['provider'])
                ->update(['is_active' => false]);
        }

        $config = AiConfig::create($validated);

        return response()->json([
            'ok' => true,
            'message' => '저장되었습니다.',
            'data' => $config,
        ]);
    }

    /**
     * AI 설정 수정
     */
    public function update(Request $request, int $id): JsonResponse
    {
        $config = AiConfig::findOrFail($id);

        $validated = $request->validate([
            'name' => 'required|string|max:50',
            'provider' => 'required|string|in:gemini,claude,openai,gcs,notion',
            'api_key' => 'nullable|string|max:255',
            'model' => 'nullable|string|max:100',
            'base_url' => 'nullable|string|max:255',
            'description' => 'nullable|string',
            'is_active' => 'boolean',
            'options' => 'nullable|array',
            'options.auth_type' => 'nullable|string|in:api_key,vertex_ai,service_account',
            'options.project_id' => 'nullable|string|max:100',
            'options.region' => 'nullable|string|max:50',
            'options.service_account_path' => 'nullable|string|max:500',
            'options.bucket_name' => 'nullable|string|max:200',
            'options.service_account_json' => 'nullable|array',
        ]);

        // GCS의 경우 별도 검증
        if ($validated['provider'] === 'gcs') {
            if (empty($validated['options']['bucket_name'])) {
                return response()->json([
                    'ok' => false,
                    'message' => '버킷 이름을 입력해주세요.',
                ], 422);
            }
            $validated['model'] = '-';
            $validated['api_key'] = 'gcs_service_account';
        } else {
            // AI 설정: Vertex AI가 아닌 경우 API 키 필수
            $authType = $validated['options']['auth_type'] ?? 'api_key';
            if ($authType !== 'vertex_ai' && empty($validated['api_key'])) {
                return response()->json([
                    'ok' => false,
                    'message' => 'API 키를 입력해주세요.',
                ], 422);
            }
        }

        // 활성화 시 동일 provider의 다른 설정 비활성화
        if ($validated['is_active'] ?? false) {
            AiConfig::where('provider', $validated['provider'])
                ->where('id', '!=', $id)
                ->update(['is_active' => false]);
        }

        $config->update($validated);

        return response()->json([
            'ok' => true,
            'message' => '수정되었습니다.',
            'data' => $config->fresh(),
        ]);
    }

    /**
     * AI 설정 삭제
     */
    public function destroy(int $id): JsonResponse
    {
        $config = AiConfig::findOrFail($id);
        $config->delete();

        return response()->json([
            'ok' => true,
            'message' => '삭제되었습니다.',
        ]);
    }

    /**
     * AI 설정 활성화/비활성화 토글
     */
    public function toggle(int $id): JsonResponse
    {
        $config = AiConfig::findOrFail($id);

        if (! $config->is_active) {
            // 활성화 시 동일 provider의 다른 설정 비활성화
            AiConfig::where('provider', $config->provider)
                ->where('id', '!=', $id)
                ->update(['is_active' => false]);
        }

        $config->update(['is_active' => ! $config->is_active]);

        return response()->json([
            'ok' => true,
            'message' => $config->is_active ? '활성화되었습니다.' : '비활성화되었습니다.',
            'data' => $config->fresh(),
        ]);
    }

    /**
     * API 연결 테스트
     */
    public function test(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'provider' => 'required|string|in:gemini,claude,openai,notion',
            'api_key' => 'nullable|string',
            'model' => 'required|string',
            'base_url' => 'nullable|string',
            'auth_type' => 'nullable|string|in:api_key,vertex_ai',
            'project_id' => 'nullable|string',
            'region' => 'nullable|string',
            'service_account_path' => 'nullable|string',
        ]);

        try {
            $provider = $validated['provider'];
            $model = $validated['model'];
            $authType = $validated['auth_type'] ?? 'api_key';

            if ($provider === 'gemini') {
                if ($authType === 'vertex_ai') {
                    // Vertex AI (서비스 계정) 방식
                    $result = $this->testGeminiVertexAi(
                        $model,
                        $validated['project_id'] ?? '',
                        $validated['region'] ?? 'us-central1',
                        $validated['service_account_path'] ?? ''
                    );
                } else {
                    // API 키 방식
                    $apiKey = $validated['api_key'] ?? '';
                    $baseUrl = $validated['base_url'] ?? AiConfig::DEFAULT_BASE_URLS[$provider];
                    $result = $this->testGemini($baseUrl, $model, $apiKey);
                }
            } else {
                return response()->json([
                    'ok' => false,
                    'error' => '아직 지원하지 않는 provider입니다.',
                ]);
            }

            return response()->json($result);
        } catch (\Exception $e) {
            return response()->json([
                'ok' => false,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Gemini API 테스트 (API 키 방식)
     */
    private function testGemini(string $baseUrl, string $model, string $apiKey): array
    {
        $url = "{$baseUrl}/models/{$model}:generateContent?key={$apiKey}";

        $response = \Illuminate\Support\Facades\Http::timeout(10)->post($url, [
            'contents' => [
                [
                    'parts' => [
                        ['text' => '안녕하세요. 테스트입니다. "OK"라고만 응답해주세요.'],
                    ],
                ],
            ],
            'generationConfig' => [
                'temperature' => 0,
                'maxOutputTokens' => 10,
            ],
        ]);

        if ($response->successful()) {
            return [
                'ok' => true,
                'message' => '연결 테스트 성공',
            ];
        }

        return [
            'ok' => false,
            'error' => 'API 응답 오류: '.$response->status(),
        ];
    }

    /**
     * Gemini API 테스트 (Vertex AI 방식)
     */
    private function testGeminiVertexAi(string $model, string $projectId, string $region, string $serviceAccountPath): array
    {
        // 필수 파라미터 검증
        if (empty($projectId)) {
            return ['ok' => false, 'error' => '프로젝트 ID가 필요합니다.'];
        }

        if (empty($serviceAccountPath)) {
            return ['ok' => false, 'error' => '서비스 계정 파일 경로가 필요합니다.'];
        }

        if (! file_exists($serviceAccountPath)) {
            return ['ok' => false, 'error' => "서비스 계정 파일을 찾을 수 없습니다: {$serviceAccountPath}"];
        }

        // 서비스 계정 JSON 로드
        $serviceAccount = json_decode(file_get_contents($serviceAccountPath), true);
        if (! $serviceAccount || empty($serviceAccount['client_email']) || empty($serviceAccount['private_key'])) {
            return ['ok' => false, 'error' => '서비스 계정 파일 형식이 올바르지 않습니다.'];
        }

        // OAuth 토큰 획득
        $accessToken = $this->getVertexAiAccessToken($serviceAccount);
        if (! $accessToken) {
            return ['ok' => false, 'error' => 'OAuth 토큰 획득 실패. 서비스 계정 권한을 확인하세요.'];
        }

        // Vertex AI 엔드포인트 URL 구성
        $url = "https://{$region}-aiplatform.googleapis.com/v1/projects/{$projectId}/locations/{$region}/publishers/google/models/{$model}:generateContent";

        $response = \Illuminate\Support\Facades\Http::timeout(30)
            ->withHeaders([
                'Authorization' => 'Bearer '.$accessToken,
                'Content-Type' => 'application/json',
            ])
            ->post($url, [
                'contents' => [
                    [
                        'role' => 'user',
                        'parts' => [
                            ['text' => '안녕하세요. 테스트입니다. "OK"라고만 응답해주세요.'],
                        ],
                    ],
                ],
                'generationConfig' => [
                    'temperature' => 0,
                    'maxOutputTokens' => 10,
                ],
            ]);

        if ($response->successful()) {
            return [
                'ok' => true,
                'message' => 'Vertex AI 연결 테스트 성공',
            ];
        }

        // 상세 오류 메시지 추출
        $errorBody = $response->json();
        $errorMsg = $errorBody['error']['message'] ?? ('HTTP '.$response->status());

        return [
            'ok' => false,
            'error' => "Vertex AI 오류: {$errorMsg}",
        ];
    }

    /**
     * Vertex AI OAuth 토큰 획득
     */
    private function getVertexAiAccessToken(array $serviceAccount): ?string
    {
        $now = time();
        $jwtHeader = $this->base64UrlEncode(json_encode(['alg' => 'RS256', 'typ' => 'JWT']));
        $jwtClaim = $this->base64UrlEncode(json_encode([
            'iss' => $serviceAccount['client_email'],
            'scope' => 'https://www.googleapis.com/auth/cloud-platform',
            'aud' => 'https://oauth2.googleapis.com/token',
            'exp' => $now + 3600,
            'iat' => $now,
        ]));

        $privateKey = openssl_pkey_get_private($serviceAccount['private_key']);
        if (! $privateKey) {
            return null;
        }

        openssl_sign($jwtHeader.'.'.$jwtClaim, $signature, $privateKey, OPENSSL_ALGO_SHA256);
        if (PHP_VERSION_ID < 80000) {
            openssl_free_key($privateKey);
        }

        $jwt = $jwtHeader.'.'.$jwtClaim.'.'.$this->base64UrlEncode($signature);

        $response = \Illuminate\Support\Facades\Http::asForm()->post('https://oauth2.googleapis.com/token', [
            'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
            'assertion' => $jwt,
        ]);

        if ($response->successful()) {
            return $response->json('access_token');
        }

        return null;
    }

    /**
     * GCS 연결 테스트
     */
    public function testGcs(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'bucket_name' => 'required|string',
            'service_account_path' => 'nullable|string',
            'service_account_json' => 'nullable|array',
        ]);

        try {
            $bucketName = $validated['bucket_name'];
            $serviceAccount = null;

            // 서비스 계정 로드 (JSON 직접 입력 또는 파일 경로)
            if (! empty($validated['service_account_json'])) {
                $serviceAccount = $validated['service_account_json'];
            } elseif (! empty($validated['service_account_path']) && file_exists($validated['service_account_path'])) {
                $serviceAccount = json_decode(file_get_contents($validated['service_account_path']), true);
            }

            if (! $serviceAccount) {
                return response()->json([
                    'ok' => false,
                    'error' => '서비스 계정 정보를 찾을 수 없습니다.',
                ]);
            }

            // OAuth 토큰 획득
            $accessToken = $this->getGcsAccessToken($serviceAccount);
            if (! $accessToken) {
                return response()->json([
                    'ok' => false,
                    'error' => 'OAuth 토큰 획득 실패',
                ]);
            }

            // 버킷 존재 확인
            $response = \Illuminate\Support\Facades\Http::timeout(10)
                ->withHeaders(['Authorization' => 'Bearer '.$accessToken])
                ->get("https://storage.googleapis.com/storage/v1/b/{$bucketName}");

            if ($response->successful()) {
                return response()->json([
                    'ok' => true,
                    'message' => "GCS 연결 성공! 버킷: {$bucketName}",
                ]);
            }

            return response()->json([
                'ok' => false,
                'error' => '버킷 접근 실패: '.$response->status(),
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'ok' => false,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * GCS OAuth 토큰 획득
     */
    private function getGcsAccessToken(array $serviceAccount): ?string
    {
        $now = time();
        $jwtHeader = $this->base64UrlEncode(json_encode(['alg' => 'RS256', 'typ' => 'JWT']));
        $jwtClaim = $this->base64UrlEncode(json_encode([
            'iss' => $serviceAccount['client_email'],
            'scope' => 'https://www.googleapis.com/auth/devstorage.full_control',
            'aud' => 'https://oauth2.googleapis.com/token',
            'exp' => $now + 3600,
            'iat' => $now,
        ]));

        $privateKey = openssl_pkey_get_private($serviceAccount['private_key']);
        if (! $privateKey) {
            return null;
        }

        openssl_sign($jwtHeader.'.'.$jwtClaim, $signature, $privateKey, OPENSSL_ALGO_SHA256);
        if (PHP_VERSION_ID < 80000) {
            openssl_free_key($privateKey);
        }

        $jwt = $jwtHeader.'.'.$jwtClaim.'.'.$this->base64UrlEncode($signature);

        $response = \Illuminate\Support\Facades\Http::asForm()->post('https://oauth2.googleapis.com/token', [
            'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
            'assertion' => $jwt,
        ]);

        if ($response->successful()) {
            return $response->json('access_token');
        }

        return null;
    }

    /**
     * Base64 URL 인코딩
     */
    private function base64UrlEncode(string $data): string
    {
        return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
    }
}
