<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use App\Models\Pasien;
use App\Models\EmbeddingWajah;

class FaceRecognitionController extends Controller
{
    /**
     * Get Flask API URL with fallback
     */
    private function getFlaskApiUrl()
    {
        return env('FLASK_API_URL', env('FACE_AI_URL', 'http://127.0.0.1:5000'));
    }

    /**
     * Check if Flask API is running
     */
    private function checkFlaskApi()
    {
        try {
            $url      = $this->getFlaskApiUrl();
            $response = Http::timeout(5)->get($url . '/health');

            if ($response->successful()) {
                Log::info('Flask API health check OK', $response->json());
                return true;
            }

            Log::warning('Flask API responded but not successful', [
                'status' => $response->status(),
                'body'   => $response->body(),
            ]);

            return false;
        } catch (\Exception $e) {
            Log::error('Flask API Health Check Failed: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Tampilkan form registrasi wajah
     */
    public function showRegisterForm($pasienId)
    {
        $pasien         = Pasien::findOrFail($pasienId);
        $flaskApiRunning = $this->checkFlaskApi();
        $flaskApiUrl    = $this->getFlaskApiUrl();

        return view('petugas.pasien.register-face', compact('pasien', 'flaskApiRunning', 'flaskApiUrl'));
    }

    /**
     * Upload foto dari kamera (base64) dan ekstraksi embedding.
     *
     * FIX v2: Blade mengirim `image_data` (base64 string dari canvas),
     * bukan file upload `foto_wajah`. Validator dan logika diubah
     * agar menerima base64 langsung — tidak ada lagi 422.
     */
    public function registerFace(Request $request)
    {
        // ── Validasi: terima image_data (base64) bukan file upload ──────────
        $validator = Validator::make($request->all(), [
            'pasien_id'  => 'required|exists:pasien,id',
            'image_data' => 'required|string',
        ], [
            'pasien_id.required'  => 'ID pasien wajib diisi',
            'pasien_id.exists'    => 'Pasien tidak ditemukan',
            'image_data.required' => 'Data gambar wajib dikirim',
            'image_data.string'   => 'Format gambar tidak valid',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validasi gagal',
                'errors'  => $validator->errors(),
            ], 422);
        }

        try {
            // ── Cek Flask API ────────────────────────────────────────────────
            if (!$this->checkFlaskApi()) {
                return response()->json([
                    'success'    => false,
                    'message'    => 'Flask API tidak dapat dihubungi',
                    'error_type' => 'FLASK_API_DOWN',
                    'flask_url'  => $this->getFlaskApiUrl(),
                    'solution'   => 'Jalankan Flask API dengan: python main.py',
                ], 503);
            }

            $pasien = Pasien::findOrFail($request->pasien_id);

            // ── Decode base64 ────────────────────────────────────────────────
            // Blade mengirim format: "data:image/jpeg;base64,/9j/4AAQ..."
            // Kita strip prefix-nya dulu jika ada.
            $base64Raw = $request->input('image_data');
            if (str_contains($base64Raw, ',')) {
                $base64Raw = explode(',', $base64Raw, 2)[1];
            }

            // Validasi apakah base64 valid
            $imageBytes = base64_decode($base64Raw, true);
            if ($imageBytes === false || strlen($imageBytes) < 100) {
                return response()->json([
                    'success' => false,
                    'message' => 'Data gambar tidak valid atau rusak',
                ], 400);
            }

            // Batasi ukuran: maks 10 MB
            $fileSizeBytes = strlen($imageBytes);
            if ($fileSizeBytes > 10 * 1024 * 1024) {
                return response()->json([
                    'success' => false,
                    'message' => 'Ukuran gambar terlalu besar (maks 10 MB)',
                ], 400);
            }

            Log::info('Processing face registration (base64)', [
                'pasien_id'   => $pasien->id,
                'pasien_name' => $pasien->nama_lengkap,
                'file_size'   => $fileSizeBytes,
            ]);

            // ── Kirim ke Flask ───────────────────────────────────────────────
            $flaskUrl = $this->getFlaskApiUrl() . '/extract-embedding';

            Log::info('Sending request to Flask API', [
                'url'               => $flaskUrl,
                'pasien_id_eksternal' => $pasien->id_eksternal,
            ]);

            $response = Http::timeout(45)
                ->retry(2, 500)
                ->post($flaskUrl, [
                    'image_data' => $base64Raw,          // kirim base64 bersih (tanpa prefix)
                    'pasien_id'  => $pasien->id_eksternal,
                ]);

            Log::info('Flask API Response', [
                'status'       => $response->status(),
                'successful'   => $response->successful(),
                'body_preview' => substr($response->body(), 0, 500),
            ]);

            if (!$response->successful()) {
                $responseData = $response->json();
                $errorMessage = $responseData['message'] ?? 'Gagal ekstraksi face embedding';
                $details      = $responseData['details'] ?? null;
                $suggestions  = $details['suggestions'] ?? [];

                Log::error('Flask API returned error', [
                    'status'  => $response->status(),
                    'message' => $errorMessage,
                    'details' => $details,
                ]);

                return response()->json([
                    'success'    => false,
                    'message'    => $errorMessage,
                    'details'    => $details,
                    'suggestions' => $suggestions,
                    'error_type' => 'FACE_DETECTION_FAILED',
                ], $response->status());
            }

            $result = $response->json();

            // ── Validasi struktur respons Flask ──────────────────────────────
            if (!isset($result['embedding']) || !isset($result['dimensions'])) {
                Log::error('Invalid response structure from Flask', ['response' => $result]);

                return response()->json([
                    'success'    => false,
                    'message'    => 'Response dari Flask API tidak valid',
                    'error_type' => 'INVALID_RESPONSE',
                ], 500);
            }

            // ── Nonaktifkan embedding lama ───────────────────────────────────
            $deactivated = EmbeddingWajah::where('pasien_id', $pasien->id)
                ->where('status_embedding', 'AKTIF')
                ->update(['status_embedding' => 'NONAKTIF']);

            if ($deactivated > 0) {
                Log::info("Deactivated {$deactivated} old embedding(s) for pasien {$pasien->id}");
            }

            // ── Simpan foto dari base64 ke storage ───────────────────────────
            $fotoFileName = 'pasien/foto/' . $pasien->id . '_' . time() . '.jpg';
            Storage::disk('public')->put($fotoFileName, $imageBytes);

            // ── Simpan embedding baru ────────────────────────────────────────
            $embedding = EmbeddingWajah::create([
                'pasien_id'               => $pasien->id,
                'id_eksternal'            => $pasien->id_eksternal,
                'vektor_embedding'        => json_encode($result['embedding']),
                'dimensi_vektor'          => $result['dimensions'] ?? 128,
                'model_encoding'          => $result['model'] ?? 'face_recognition',
                'versi_model'             => $result['model_version'] ?? null,
                'skor_kepercayaan'        => $result['confidence'] ?? 0,
                'kualitas_gambar'         => match (strtoupper($result['quality'] ?? 'BAIK')) {
                    'SANGAT BAIK', 'SANGAT_BAIK' => 'SANGAT BAIK',
                    'BURUK'                      => 'RENDAH',
                    default                      => strtoupper($result['quality'] ?? 'BAIK'),
                },
                'koordinat_wajah'         => isset($result['face_location']) ? json_encode($result['face_location']) : null,
                'jumlah_wajah_terdeteksi' => 1,
                'validasi_passed'         => ($result['confidence'] ?? 0) >= 70,
                'status_embedding'        => 'AKTIF',
                'resolusi_gambar'         => $result['image_resolution'] ?? null,
                'ukuran_gambar_kb'        => round($fileSizeBytes / 1024, 2),
                'didaftarkan_oleh'        => auth()->id(),
                'ip_address'              => $request->ip(),
                'user_agent'              => $request->userAgent(),
                'tanggal_registrasi'      => now(),
            ]);

            // ── Update status pasien ─────────────────────────────────────────
            $pasien->update([
                'wajah_terdaftar'          => true,
                'tanggal_registrasi_wajah' => now(),
                'foto_profil'              => $fotoFileName,
            ]);

            Log::info('Face embedding successfully registered', [
                'embedding_id'     => $embedding->id,
                'pasien_id'        => $pasien->id,
                'quality'          => $result['quality'] ?? 'UNKNOWN',
                'confidence'       => $result['confidence'] ?? 0,
                'detection_method' => $result['detection_method'] ?? 'UNKNOWN',
            ]);

            return response()->json([
                'success' => true,
                'message' => 'Face embedding berhasil didaftarkan',
                'data'    => [
                    'id'               => $embedding->id,
                    'model_encoding'   => $embedding->model_encoding,
                    'skor_kepercayaan' => $embedding->skor_kepercayaan,
                    'kualitas_gambar'  => $embedding->kualitas_gambar,
                    'dimensi_vektor'   => $embedding->dimensi_vektor,
                    'detection_method' => $result['detection_method'] ?? null,
                    'face_ratio'       => $result['face_ratio'] ?? null,
                ],
            ], 201);

        } catch (\Illuminate\Http\Client\ConnectionException $e) {
            Log::error('Flask API Connection Error', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            return response()->json([
                'success'    => false,
                'message'    => 'Tidak dapat terhubung ke Flask API',
                'error_type' => 'CONNECTION_ERROR',
                'flask_url'  => $this->getFlaskApiUrl(),
                'solution'   => 'Pastikan Flask API sedang berjalan. Jalankan: python main.py',
            ], 503);

        } catch (\Illuminate\Http\Client\RequestException $e) {
            $flaskResponse = $e->response;
            $statusCode    = $flaskResponse ? $flaskResponse->status() : 500;
            $responseData  = [];

            try {
                $responseData = $flaskResponse ? $flaskResponse->json() : [];
            } catch (\Exception $jsonEx) {
                // response bukan JSON
            }

            $errorMessage = $responseData['message'] ?? 'Error saat berkomunikasi dengan Flask API';
            $reason       = $responseData['reason']  ?? null;
            $hint         = $responseData['hint']    ?? null;

            Log::error('Flask API Request Error', [
                'error'          => $e->getMessage(),
                'flask_status'   => $statusCode,
                'flask_response' => $responseData,
            ]);

            return response()->json([
                'success'    => false,
                'message'    => $errorMessage,
                'reason'     => $reason,
                'hint'       => $hint,
                'error_type' => 'FACE_DETECTION_FAILED',
            ], $statusCode);

        } catch (\Exception $e) {
            Log::error('Face Registration Error', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'file'  => $e->getFile(),
                'line'  => $e->getLine(),
            ]);

            return response()->json([
                'success'    => false,
                'message'    => 'Terjadi kesalahan saat registrasi wajah',
                'error_type' => 'GENERAL_ERROR',
                'details'    => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }

    /**
     * Identify pasien dari foto wajah (file upload)
     */
    public function identifyFace(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'foto_wajah' => 'required|image|mimes:jpeg,png,jpg|max:5120',
        ], [
            'foto_wajah.required' => 'Foto wajah harus diupload',
            'foto_wajah.image'    => 'File harus berupa gambar',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validasi gagal',
                'errors'  => $validator->errors(),
            ], 422);
        }

        try {
            if (!$this->checkFlaskApi()) {
                return response()->json([
                    'success'    => false,
                    'message'    => 'Flask API tidak dapat dihubungi',
                    'error_type' => 'FLASK_API_DOWN',
                ], 503);
            }

            $imagePath = $request->file('foto_wajah')->getRealPath();
            $imageData = base64_encode(file_get_contents($imagePath));

            Log::info('Processing face identification');

            $response = Http::timeout(45)
                ->retry(2, 500)
                ->post($this->getFlaskApiUrl() . '/identify-face', [
                    'image_data' => $imageData,
                ]);

            if (!$response->successful()) {
                $responseData = $response->json();
                $errorMessage = $responseData['message'] ?? 'Gagal identifikasi wajah';

                Log::error('Face identification failed', [
                    'status'   => $response->status(),
                    'message'  => $errorMessage,
                    'response' => $responseData,
                ]);

                return response()->json([
                    'success' => false,
                    'message' => $errorMessage,
                    'details' => $responseData['details'] ?? null,
                ], $response->status());
            }

            $result = $response->json();

            if (!isset($result['found']) || !$result['found']) {
                return response()->json([
                    'success' => false,
                    'message' => 'Wajah tidak dikenali dalam database',
                    'details' => $result['details'] ?? null,
                ], 404);
            }

            $pasien = Pasien::where('id_eksternal', $result['pasien_id'])->first();

            if (!$pasien) {
                Log::error('Pasien not found for identified face', [
                    'pasien_id_eksternal' => $result['pasien_id'],
                ]);

                return response()->json([
                    'success'    => false,
                    'message'    => 'Data pasien tidak ditemukan dalam sistem',
                    'error_type' => 'PASIEN_NOT_FOUND',
                ], 404);
            }

            $embedding = $pasien->embeddingWajahAktif;
            if ($embedding) {
                $embedding->increment('total_dikenali');
                $embedding->update(['terakhir_dikenali' => now()]);
            }

            Log::info('Face identified successfully', [
                'pasien_id'   => $pasien->id,
                'pasien_name' => $pasien->nama_lengkap,
                'similarity'  => $result['similarity_score'] ?? 0,
                'confidence'  => $result['confidence'] ?? 'UNKNOWN',
            ]);

            return response()->json([
                'success' => true,
                'message' => 'Pasien berhasil diidentifikasi',
                'data'    => [
                    'pasien' => [
                        'id'             => $pasien->id,
                        'nama_lengkap'   => $pasien->nama_lengkap,
                        'no_rekam_medis' => $pasien->no_rekam_medis,
                        'nik'            => $pasien->nik,
                        'jenis_kelamin'  => $pasien->jenis_kelamin,
                        'tanggal_lahir'  => $pasien->tanggal_lahir,
                        'usia'           => $pasien->usia,
                        'foto_profil'    => $pasien->foto_profil ? asset('storage/' . $pasien->foto_profil) : null,
                    ],
                    'similarity_score'   => $result['similarity_score'] ?? 0,
                    'confidence'         => $result['confidence'] ?? 'UNKNOWN',
                    'detection_method'   => $result['detection_method'] ?? null,
                ],
            ]);

        } catch (\Illuminate\Http\Client\ConnectionException $e) {
            Log::error('Flask API Connection Error (Identify)', ['error' => $e->getMessage()]);

            return response()->json([
                'success'    => false,
                'message'    => 'Tidak dapat terhubung ke Flask API',
                'error_type' => 'CONNECTION_ERROR',
            ], 503);

        } catch (\Exception $e) {
            Log::error('Face Identification Error', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            return response()->json([
                'success'    => false,
                'message'    => 'Terjadi kesalahan saat identifikasi wajah',
                'error_type' => 'GENERAL_ERROR',
                'details'    => config('app.debug') ? $e->getMessage() : null,
            ], 500);
        }
    }

    /**
     * Test Flask API connection
     */
    public function testFlaskApi()
    {
        try {
            $url      = $this->getFlaskApiUrl();
            $response = Http::timeout(5)->get($url . '/health');

            if ($response->successful()) {
                return response()->json([
                    'success' => true,
                    'message' => 'Flask API is running',
                    'url'     => $url,
                    'data'    => $response->json(),
                ]);
            }

            return response()->json([
                'success' => false,
                'message' => 'Flask API responded but with error',
                'url'     => $url,
                'status'  => $response->status(),
                'body'    => $response->body(),
            ], $response->status());

        } catch (\Exception $e) {
            return response()->json([
                'success'  => false,
                'message'  => 'Cannot connect to Flask API',
                'url'      => $this->getFlaskApiUrl(),
                'error'    => $e->getMessage(),
                'solution' => 'Please run: python main.py',
            ], 503);
        }
    }
}