<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Validation\ValidationException;
use App\Models\User;
use App\Models\Zone;

class AuthController extends Controller
{
    /**
     * Menampilkan halaman login
     */
    public function showLogin()
    {
        return view('auth.login');
    }

    /**
     * Menampilkan halaman lupa password
     */
    public function showForgotPassword()
    {
        return view('auth.forgot-password');
    }

    /**
     * Memproses pengiriman tautan reset password
     */
    public function sendResetLinkEmail(Request $request)
    {
        $request->validate(['email' => 'required|email']);

        $user = \App\Models\User::where('email', $request->email)->first();

        if ($user) {
            // Bypass Laravel Mail Throttle (batas 60 detik) untuk keperluan testing lokal
            $token = app('auth.password.broker')->createToken($user);
            return redirect()->route('password.reset', ['token' => $token, 'email' => $request->email]);
        }

        return back()->withInput()->withErrors(['email' => 'Email belum terdaftar, tidak bisa ganti password']);
    }

    /**
     * Menampilkan halaman reset password (diakses dari link email)
     */
    public function showResetForm(Request $request, $token = null)
    {
        return view('auth.reset-password')->with(
            ['token' => $token, 'email' => $request->email]
        );
    }

    /**
     * Memproses penggantian password
     */
    public function reset(Request $request)
    {
        $request->validate([
            'token' => 'required',
            'email' => 'required|email',
            'password' => 'required|confirmed',
        ]);

        $status = Password::reset(
            $request->only('email', 'password', 'password_confirmation', 'token'),
            function ($user, $password) {
                // Pastikan password dihash di sini karena booted() User model hanya meng-hash saat 'creating'
                $user->forceFill([
                    'password' => Hash::make($password)
                ])->save();
            }
        );

        return $status === Password::PASSWORD_RESET
                    ? redirect()->route('login')->with('status', __($status))
                    : back()->withErrors(['email' => [__($status)]]);
    }

    public function login(Request $request)
    {
        $credentials = $request->validate([
            'email' => ['required', 'email'],
            'password' => ['required'],
        ]);

        if (Auth::attempt($credentials)) {
            $request->session()->regenerate();

            if (Auth::user()->role === 'admin') {
                return redirect()->route('admin.dashboard');
            } elseif (Auth::user()->role === 'kurir') {
                return redirect()->route('kurir.dashboard');
            }
            
            return redirect()->route('user.dashboard');
        }

        return back()->withErrors([
            'email' => 'Email atau password yang Anda masukkan salah',
        ])->onlyInput('email');
    }

    /**
     * Menampilkan halaman register
     */
    public function showRegister()
    {
        return view('auth.register');
    }

    /**
     * Memproses data pendaftaran kurir baru
     */
    public function register(Request $request)
    {
        $request->validate([
            'name'     => ['required', 'string', 'max:18', 'regex:/^[^0-9]+$/'],
            'email'    => ['required', 'string', 'email', 'max:30', 'unique:users'],
            'password' => ['required', 'confirmed'],
            'phone'    => ['required', 'string', 'max:12', 'regex:/^[0-9]+$/'],
            'address'  => ['required', 'string'],
            'kecamatan' => ['required', 'string', 'max:100'],
            'kabupaten' => ['required', 'string', 'max:100'],
        ], [
            'name.max'          => 'Nama tidak boleh lebih dari 18 karakter',
            'name.regex'        => 'Nama tidak boleh mengandung angka',
            'email.max'         => 'Email tidak boleh lebih dari 30 karakter',
            'email.unique'      => 'Email ini sudah digunakan',
            'phone.max'         => 'Nomor HP terlalu panjang',
            'phone.regex'       => 'Nomor WhatsApp hanya boleh berisi angka',
            'password.confirmed'=> 'Konfirmasi password tidak cocok',
            'kecamatan.required'=> 'Kecamatan wajib dipilih',
            'kabupaten.required'=> 'Kabupaten wajib diisi',
        ]);

        // ── Strict Address Kelurahan-Only Check (Kec/Kab exclusion) ───────────────
        if (preg_match('/\b(kec|kecamatan|kab|kabupaten)\b/i', $request->address) && !preg_match('/(latitude|longitude)/i', $request->address)) {
            return back()->withErrors(['address' => 'Cukup tuliskan alamat lengkap Anda sampai nama Kelurahan/Desa saja (Contoh: Kp Sentul RT 04 RW 04 Kel Curug Kulon). Tidak perlu menuliskan Kecamatan dan Kabupaten/Kota di kolom ini karena sudah dipilih di bawah'])->withInput();
        }

        // ── Strict Regency Validation ─────────────────────────────────────────────
        $senderKabupaten = 'Kabupaten Tangerang';
        if (!str_contains(strtolower($request->kabupaten), strtolower($senderKabupaten))) {
            return back()->withErrors(['kabupaten' => 'Maaf, kami hanya melayani area ' . $senderKabupaten])->withInput();
        }

        // ── Strict Kecamatan Validation ───────────────────────────────────────────
        $zoneExists = \App\Models\Zone::whereRaw('LOWER(name) = ?', [strtolower(trim($request->kecamatan))])->exists();
        if (!$zoneExists) {
            return back()->withErrors(['kecamatan' => 'Maaf, kecamatan yang Anda pilih belum masuk dalam area jangkauan pengiriman kami'])->withInput();
        }

        // ── Strict Address Keywords Check (Anti-Bypass) ───────────────────────────
        $restrictedKeywords = ['bogor', 'jakarta', 'depok', 'bekasi', 'serang', 'cilegon', 'lebak', 'pandeglang', 'bandung', 'sukabumi', 'karawang'];
        foreach ($restrictedKeywords as $keyword) {
            if (str_contains(strtolower($request->address), $keyword)) {
                return back()->withErrors(['address' => "Maaf, alamat lengkap Anda terdeteksi berada di luar area layanan kami (terdeteksi wilayah: {$keyword}). Kami hanya melayani pengiriman Kabupaten Tangerang"])->withInput();
            }
        }

        // ── Resolve Zone (GPS & Text Fallback) ────────────────────────────────────
        $lat = null;
        $lng = null;
        $zoneId = null;
        $titikKoordinat = trim($request->titik_koordinat ?? '');

        // Prioritas 1: koordinat dari field titik_koordinat (format: "-6.123, 106.456")
        if (!empty($titikKoordinat) && preg_match('/^([-\d\.]+),\s*([-\d\.]+)$/', $titikKoordinat, $m)) {
            $lat = (float) $m[1];
            $lng = (float) $m[2];
        }
        // Prioritas 2: koordinat lama yang masih tertanam di teks address (backward compat)
        elseif (preg_match('/Latitude:\s*([-\d\.]+),\s*Longitude:\s*([-\d\.]+)/i', $request->address, $matches)) {
            $lat = (float) $matches[1];
            $lng = (float) $matches[2];
            // Simpan ke titikKoordinat supaya konsisten
            $titikKoordinat = "$lat, $lng";
        }

        if ($lat !== null && $lng !== null) {
            $senderLat = -6.2569093;
            $senderLng = 106.5582734;

            $earthRadius = 6371; // km
            $dLat = deg2rad($lat - $senderLat);
            $dLon = deg2rad($lng - $senderLng);

            $a = sin($dLat/2) * sin($dLat/2) +
                 cos(deg2rad($senderLat)) * cos(deg2rad($lat)) *
                 sin($dLon/2) * sin($dLon/2);
            $c = 2 * atan2(sqrt($a), sqrt(1-$a));
            $distance = $earthRadius * $c;

            $targetType = 'local';
            if ($distance > 2.0 && $distance <= 5.0) {
                $targetType = 'nearby';
            } elseif ($distance > 5.0) {
                $targetType = 'far';
            }

            // Cari zone dengan kecamatan yang cocok, jika tidak ada, gunakan sebarang zone dengan tipe tersebut
            $zone = Zone::whereRaw('LOWER(name) = ?', [strtolower(trim($request->kecamatan))])->first();
            if (!$zone) {
                $zone = Zone::where('zone_type', $targetType)->first();
            }
            $zoneId = $zone?->id_zones;
        } else {
            $zone = Zone::whereRaw('LOWER(name) = ?', [strtolower(trim($request->kecamatan))])
                        ->first();
            $zoneId = $zone?->id_zones;
        }

        $user = User::create([
            'name'     => $request->name,
            'email'    => $request->email,
            'password' => Hash::make($request->password),
            'role'     => 'user',
            'phone'    => $request->phone,
            'address'  => $request->address,
        ]);

        // Mendaftarkan pelanggan dengan data zona
        \App\Models\Pelanggan::create([
            'customers_id'    => $user->id_user,
            'name'            => $request->name,
            'phone'           => $request->phone,
            'address'         => $request->address,
            'kecamatan'       => $request->kecamatan,
            'kabupaten'       => $request->kabupaten,
            'id_zones'        => $zoneId,
            'price_category'  => 0,
            'titik_koordinat' => $titikKoordinat ?: null,
        ]);

        if (Auth::check() && Auth::user()->role === 'admin') {
            return redirect()->route('admin.pelanggan')->with('success', 'Pelanggan baru berhasil didaftarkan sebagai pengguna.');
        }

        return redirect()->route('register')->with('success', 'Akun berhasil dibuat! Silakan masuk ke sistem.');
    }

    /**
     * API: Validasi kabupaten & zona kecamatan secara real-time.
     * GET /check-zone?kabupaten=...&kecamatan=...
     *
     * Response JSON:
     *   { status: 'blocked'|'warning'|'success', message: '...', zone_type: '...', cost: 0 }
     */
    public function checkZone(Request $request)
    {
        $senderKabupaten = 'Kabupaten Tangerang';
        $inputKabupaten  = trim($request->get('kabupaten', ''));
        $inputKecamatan  = trim($request->get('kecamatan', ''));
        $inputAddress    = trim($request->get('address', ''));

        // Retrieve shipping costs from PriceSetting with hardcoded fallbacks
        $zone1_3kg = (float) (\App\Models\PriceSetting::where('id_price_setting', 'ZONE_1_3KG')->value('price') ?? 500);
        $zone1_big = (float) (\App\Models\PriceSetting::where('id_price_setting', 'ZONE_1_BIG')->value('price') ?? 1000);
        $zone2_3kg = (float) (\App\Models\PriceSetting::where('id_price_setting', 'ZONE_2_3KG')->value('price') ?? 1000);
        $zone2_big = (float) (\App\Models\PriceSetting::where('id_price_setting', 'ZONE_2_BIG')->value('price') ?? 2000);
        $zone3_3kg = (float) (\App\Models\PriceSetting::where('id_price_setting', 'ZONE_3_3KG')->value('price') ?? 2000);
        $zone3_big = (float) (\App\Models\PriceSetting::where('id_price_setting', 'ZONE_3_BIG')->value('price') ?? 3000);

        // ── 0. Auto-detect Kecamatan from address if empty ────────────────────────
        if (empty($inputKecamatan) && !empty($inputAddress)) {
            if (preg_match('/(?:kecamatan|kec\.?)\s+([a-zA-Z\s]{3,20})/i', $inputAddress, $matches)) {
                $inputKecamatan = trim($matches[1]);
            }
        }

        // ── 1. Strict Address Keywords Check ───────────────────────────────────────
        if (!empty($inputAddress)) {
            $restrictedKeywords = ['bogor', 'jakarta', 'depok', 'bekasi', 'serang', 'cilegon', 'lebak', 'pandeglang', 'bandung', 'sukabumi', 'karawang'];
            foreach ($restrictedKeywords as $keyword) {
                if (str_contains(strtolower($inputAddress), $keyword)) {
                    return response()->json([
                        'status'    => 'blocked',
                        'zone_type' => null,
                        'cost'      => 0,
                        'message'   => "Maaf, alamat lengkap Anda terdeteksi berada di luar area layanan kami (terdeteksi wilayah: {$keyword}). Kami hanya melayani pengiriman Kabupaten Tangerang.",
                    ]);
                }
            }
        }

        // ── 2. Strict regency check ───────────────────────────────────────────────
        if (!empty($inputKabupaten) &&
            !str_contains(strtolower($inputKabupaten), strtolower($senderKabupaten))) {
            return response()->json([
                'status'    => 'blocked',
                'zone_type' => null,
                'cost'      => 0,
                'message'   => "Maaf, demi keamanan pengiriman, kami hanya melayani area {$senderKabupaten}. Silakan cari agen terdekat di lokasi Anda.",
            ]);
        }

        // ── 3. GPS Coordinates Distance Check (Highly Accurate Geolocation) ───────
        $lat = null;
        $lng = null;

        // Prioritas 1: Parameter coords terpisah (dikirim dari form register via JS)
        $inputCoords = trim($request->get('coords', ''));
        if (!empty($inputCoords) && preg_match('/^([-\d\.]+),\s*([-\d\.]+)$/', $inputCoords, $m)) {
            $lat = (float) $m[1];
            $lng = (float) $m[2];
        }

        // Prioritas 2: Koordinat tertanam di teks address (format lama)
        if ($lat === null && preg_match('/Latitude:\s*([-\d\.]+),\s*Longitude:\s*([-\d\.]+)/i', $inputAddress, $matches)) {
            $lat = (float) $matches[1];
            $lng = (float) $matches[2];
        }

        if ($lat !== null && $lng !== null) {
            // Home Base / Sender Location (Curug, Kabupaten Tangerang)
            $senderLat = -6.2569093;
            $senderLng = 106.5582734;

            // Haversine Formula
            $earthRadius = 6371; // km
            $dLat = deg2rad($lat - $senderLat);
            $dLon = deg2rad($lng - $senderLng);

            $a = sin($dLat/2) * sin($dLat/2) +
                 cos(deg2rad($senderLat)) * cos(deg2rad($lat)) *
                 sin($dLon/2) * sin($dLon/2);
            $c = 2 * atan2(sqrt($a), sqrt(1-$a));
            $distance = $earthRadius * $c; // in km

            // Define zones based on actual GPS distance:
            if ($distance <= 2.0) {
                // Zona 1 (Lokal)
                return response()->json([
                    'status'    => 'success',
                    'zone_type' => 'local',
                    'cost_3kg'  => $zone1_3kg,
                    'cost_big'  => $zone1_big,
                    'message'   => "Lokasi Anda terdeteksi GPS berjarak " . number_format($distance, 2) . " km dari pengirim (Zona 1 - Lokal).",
                    'distance'  => $distance,
                ]);
            } elseif ($distance <= 5.0) {
                // Zona 2 (Sedang)
                return response()->json([
                    'status'    => 'success',
                    'zone_type' => 'nearby',
                    'cost_3kg'  => $zone2_3kg,
                    'cost_big'  => $zone2_big,
                    'message'   => "Lokasi Anda terdeteksi GPS berjarak " . number_format($distance, 2) . " km dari pengirim (Zona 2 - Sedang).",
                    'distance'  => $distance,
                ]);
            } else {
                // Zona 3 (Jauh)
                return response()->json([
                    'status'    => 'warning',
                    'zone_type' => 'far',
                    'cost_3kg'  => $zone3_3kg,
                    'cost_big'  => $zone3_big,
                    'message'   => "Lokasi Anda terdeteksi GPS berjarak " . number_format($distance, 2) . " km dari pengirim (Zona 3 - Jauh). Ongkos kirim tambahan per tabung Rp" . number_format($zone3_3kg, 0, ',', '.') . " (3kg) & Rp" . number_format($zone3_big, 0, ',', '.') . " (5,5kg & 12kg) dikenakan. Setuju?",
                    'distance'  => $distance,
                ]);
            }
        }

        // ── 4. Fallback Zone Text Matching (Kecamatan) ───────────────────────────
        if (!empty($inputKecamatan)) {
            $zone = Zone::whereRaw('LOWER(name) = ?', [strtolower($inputKecamatan)])
                        ->first();

            if (!$zone) {
                // Kecamatan not in our database — treat as nearby (safe default)
                return response()->json([
                    'status'    => 'success',
                    'zone_type' => 'nearby',
                    'cost_3kg'  => $zone2_3kg,
                    'cost_big'  => $zone2_big,
                    'message'   => 'Kecamatan ditemukan. Ongkos kirim standar berlaku.',
                ]);
            }

            if ($zone->zone_type === 'far') {
                return response()->json([
                    'status'    => 'warning',
                    'zone_type' => 'far',
                    'cost_3kg'  => $zone3_3kg,
                    'cost_big'  => $zone3_big,
                    'message'   => "Lokasi Anda termasuk zona jauh. Ongkos kirim tambahan per tabung sebesar Rp" . number_format($zone3_3kg, 0, ',', '.') . " (3kg) & Rp" . number_format($zone3_big, 0, ',', '.') . " (5,5kg & 12kg) akan dikenakan. Apakah Anda setuju?",
                    'zone_name' => $zone->name,
                ]);
            }

            $zoneType = $zone->zone_type;
            $cost3kg = ($zoneType === 'local') ? $zone1_3kg : $zone2_3kg;
            $costBig = ($zoneType === 'local') ? $zone1_big : $zone2_big;

            return response()->json([
                'status'    => 'success',
                'zone_type' => $zoneType,
                'cost_3kg'  => $cost3kg,
                'cost_big'  => $costBig,
                'message'   => 'Lokasi Anda berada dalam area layanan kami.',
                'zone_name' => $zone->name,
            ]);
        }

        // Belum ada input yang cukup — biarkan form berjalan normal
        return response()->json([
            'status'    => 'idle',
            'zone_type' => null,
            'cost_3kg'  => 0,
            'cost_big'  => 0,
            'message'   => '',
        ]);
    }

    /**
     * API: Reverse Geocoding via Google Maps API (fallback to OpenStreetMap Nominatim)
     * GET /reverse-geocode?lat=...&lng=...
     */
    public function reverseGeocode(Request $request)
    {
        $lat = $request->get('lat');
        $lng = $request->get('lng');

        if (!$lat || !$lng) {
            return response()->json(['error' => 'Coordinates missing'], 400);
        }

        $apiKey = env('GOOGLE_MAPS_API_KEY');

        if ($apiKey) {
            try {
                $url = "https://maps.googleapis.com/maps/api/geocode/json?latlng={$lat},{$lng}&key={$apiKey}&language=id";
                $response = \Illuminate\Support\Facades\Http::get($url);
                if ($response->successful()) {
                    $data = $response->json();
                    if (!empty($data['results'])) {
                        $kecamatan = '';
                        $kelurahan = '';
                        $kabupaten = '';

                        $jalan = '';
                        $kelurahan_text = '';
                        foreach ($data['results'][0]['address_components'] as $component) {
                            $types = $component['types'];
                            if (in_array('administrative_area_level_3', $types)) {
                                $kecamatan = $component['long_name'];
                            } elseif (in_array('administrative_area_level_4', $types)) {
                                $kelurahan = $component['long_name'];
                                $kelurahan_text = 'Kel. ' . $component['long_name'];
                            } elseif (in_array('administrative_area_level_2', $types)) {
                                $kabupaten = $component['long_name'];
                            } elseif (in_array('route', $types)) {
                                $jalan = $component['long_name'];
                            } elseif (in_array('neighborhood', $types) && empty($jalan)) {
                                $jalan = 'Kp. ' . $component['long_name'];
                            }
                        }

                        $addressParts = array_filter([$jalan, $kelurahan_text]);
                        $formattedAddress = implode(', ', $addressParts);

                        return response()->json([
                            'source'            => 'google',
                            'kecamatan'         => $kecamatan,
                            'kelurahan'         => $kelurahan,
                            'kabupaten'         => $kabupaten,
                            'formatted_address' => $formattedAddress,
                        ]);
                    }
                }
            } catch (\Exception $e) {
                // fall through to Nominatim
            }
        }

        // Fallback: OpenStreetMap Nominatim
        try {
            $url = "https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat={$lat}&lon={$lng}";
            $response = \Illuminate\Support\Facades\Http::withHeaders([
                'User-Agent' => 'GasKu-LPG-App/1.0',
                'Accept-Language' => 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7'
            ])->get($url);

            if ($response->successful()) {
                $data = $response->json();
                $address = $data['address'] ?? [];
                
                $kecamatan = $address['subdistrict'] ?? $address['city_district'] ?? $address['district'] ?? $address['town'] ?? $address['municipality'] ?? '';
                $kelurahan = $address['village'] ?? $address['suburb'] ?? $address['neighbourhood'] ?? '';
                $kabupaten = $address['county'] ?? $address['city'] ?? $address['city_district'] ?? '';

                // Bangun alamat lengkap yang mudah dibaca
                $parts = [];
                if (!empty($address['road']))        $parts[] = $address['road'];
                elseif (!empty($address['hamlet']))  $parts[] = 'Kp. ' . $address['hamlet'];
                if (!empty($address['house_number'])) $parts[0] = ($parts[0] ?? '') . ' No.' . $address['house_number'];
                if (!empty($address['village']))     $parts[] = 'Desa ' . $address['village'];
                elseif (!empty($address['suburb']))  $parts[] = 'Kel. ' . $address['suburb'];
                elseif (!empty($address['neighbourhood'])) $parts[] = 'Kel. ' . $address['neighbourhood'];
                $formattedAddress = implode(', ', array_filter($parts));

                return response()->json([
                    'source'            => 'nominatim',
                    'kecamatan'         => $kecamatan,
                    'kelurahan'         => $kelurahan,
                    'kabupaten'         => $kabupaten,
                    'formatted_address' => $formattedAddress,
                    'raw_address'       => $address,
                ]);
            }
        } catch (\Exception $e) {
            // ignore
        }

        return response()->json(['error' => 'Geocoding failed'], 500);
    }


    /**
     * Logout
     */
    public function logout(Request $request)
    {
        Auth::logout();
        $request->session()->invalidate();
        $request->session()->regenerateToken();

        return redirect('/login');
    }

    public function checkEmail(Request $request)
    {
        $email = $request->get('email');
        $id = $request->get('id');
        $exists = User::where('email', $email)
            ->when($id, function($query) use ($id) {
                return $query->where('id_user', '!=', $id);
            })->exists();
        return response()->json(['exists' => $exists]);
    }

    public function checkPhone(Request $request)
    {
        $phone = $request->get('phone');
        $id = $request->get('id');
        $exists = User::where('phone', $phone)
            ->when($id, function($query) use ($id) {
                return $query->where('id_user', '!=', $id);
            })->exists();
        return response()->json(['exists' => $exists]);
    }
}
