<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Booking;
use App\Models\Lapangan;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Validator;
use Carbon\Carbon;

class BookingController extends Controller
{
    // =============================================
    // FORMAT RESPONSE HELPER
    // =============================================

    private function successResponse(string $message, $data = null, int $code = 200): JsonResponse
    {
        return response()->json(['success' => true, 'message' => $message, 'data' => $data], $code);
    }

    private function errorResponse(string $message, $errors = null, int $code = 400): JsonResponse
    {
        $res = ['success' => false, 'message' => $message];
        if ($errors !== null) $res['errors'] = $errors;
        return response()->json($res, $code);
    }

    // =============================================
    // STORE - Buat booking baru (customer)
    // =============================================

    /**
     * Buat booking baru
     * Cek bentrok jadwal sebelum menyimpan
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function store(Request $request): JsonResponse
    {
        try {
            // Validasi input
            $validator = Validator::make($request->all(), [
                'lapangan_id' => 'required|integer|exists:lapangan,id',
                'tanggal'     => 'required|date|date_format:Y-m-d|after_or_equal:today',
                'jam_mulai'   => 'required|date_format:H:i',
                'jam_selesai' => 'required|date_format:H:i|after:jam_mulai',
                'catatan'     => 'nullable|string|max:500',
            ], [
                'lapangan_id.required'  => 'Lapangan wajib dipilih.',
                'lapangan_id.exists'    => 'Lapangan tidak ditemukan.',
                'tanggal.required'      => 'Tanggal wajib diisi.',
                'tanggal.after_or_equal' => 'Tanggal booking tidak boleh di masa lalu.',
                'jam_mulai.required'    => 'Jam mulai wajib diisi.',
                'jam_selesai.required'  => 'Jam selesai wajib diisi.',
                'jam_selesai.after'     => 'Jam selesai harus setelah jam mulai.',
            ]);

            if ($validator->fails()) {
                return $this->errorResponse('Validasi gagal.', $validator->errors(), 422);
            }

            // Cek apakah lapangan aktif
            $lapangan = Lapangan::find($request->lapangan_id);
            if (!$lapangan->is_active) {
                return $this->errorResponse('Lapangan sedang tidak aktif.', null, 400);
            }

            // Cek jam operasional lapangan
            $jamMulai   = $request->jam_mulai . ':00';
            $jamSelesai = $request->jam_selesai . ':00';

            if ($jamMulai < $lapangan->jam_buka || $jamSelesai > $lapangan->jam_tutup) {
                return $this->errorResponse(
                    "Jam booking di luar jam operasional lapangan ({$lapangan->jam_buka} - {$lapangan->jam_tutup}).",
                    null,
                    400
                );
            }

            // Cek bentrok jadwal dengan booking yang sudah ada
            $conflictingBooking = Booking::where('lapangan_id', $request->lapangan_id)
                ->whereDate('tanggal', $request->tanggal)
                ->whereIn('status', ['pending', 'confirmed'])
                ->where(function ($query) use ($request) {
                    $query->where(function ($q) use ($request) {
                        // Booking baru mulai di tengah-tengah booking lain
                        $q->where('jam_mulai', '<', $request->jam_selesai . ':00')
                            ->where('jam_selesai', '>', $request->jam_mulai . ':00');
                    });
                })
                ->first();

            if ($conflictingBooking) {
                return $this->errorResponse(
                    "Jadwal bentrok dengan booking lain ({$conflictingBooking->jam_mulai} - {$conflictingBooking->jam_selesai}). Silakan pilih jam lain.",
                    null,
                    409
                );
            }

            // Hitung durasi dan total harga
            $mulai      = Carbon::createFromFormat('H:i', $request->jam_mulai);
            $selesai    = Carbon::createFromFormat('H:i', $request->jam_selesai);
            $durasiJam  = $selesai->diffInHours($mulai);
            $totalHarga = $lapangan->harga_per_jam * $durasiJam;

            // Buat booking
            $booking = Booking::create([
                'user_id'     => $request->user()->id,
                'lapangan_id' => $request->lapangan_id,
                'tanggal'     => $request->tanggal,
                'jam_mulai'   => $request->jam_mulai . ':00',
                'jam_selesai' => $request->jam_selesai . ':00',
                'durasi_jam'  => $durasiJam,
                'total_harga' => $totalHarga,
                'status'      => 'pending',
                'catatan'     => $request->catatan,
            ]);

            $booking->load(['user:id,name,email,phone', 'lapangan:id,nama,lokasi,alamat,harga_per_jam,foto']);

            return $this->successResponse(
                'Booking berhasil dibuat. Menunggu konfirmasi admin.',
                $this->formatBooking($booking),
                201
            );
        } catch (\Exception $e) {
            return $this->errorResponse('Terjadi kesalahan server: ' . $e->getMessage(), null, 500);
        }
    }

    // =============================================
    // MY BOOKINGS - Booking milik user yang login
    // =============================================

    /**
     * Ambil semua booking milik user yang login
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function myBookings(Request $request): JsonResponse
    {
        try {
            $query = Booking::with(['lapangan:id,nama,lokasi,foto,harga_per_jam,jenis_olahraga'])
                ->where('user_id', $request->user()->id)
                ->orderByDesc('created_at');

            // Filter berdasarkan status
            if ($request->filled('status')) {
                $query->where('status', $request->status);
            }

            // Filter berdasarkan tanggal
            if ($request->filled('tanggal')) {
                $query->whereDate('tanggal', $request->tanggal);
            }

            $perPage  = min((int) $request->get('per_page', 15), 100);
            $bookings = $query->paginate($perPage);

            return $this->successResponse('Data booking Anda berhasil diambil.', [
                'items'        => $bookings->map(fn($b) => $this->formatBooking($b)),
                'current_page' => $bookings->currentPage(),
                'last_page'    => $bookings->lastPage(),
                'per_page'     => $bookings->perPage(),
                'total'        => $bookings->total(),
            ]);
        } catch (\Exception $e) {
            return $this->errorResponse('Terjadi kesalahan server: ' . $e->getMessage(), null, 500);
        }
    }

    // =============================================
    // SHOW - Detail booking
    // =============================================

    /**
     * Ambil detail booking berdasarkan ID
     *
     * @param Request $request
     * @param int     $id
     * @return JsonResponse
     */
    public function show(Request $request, int $id): JsonResponse
    {
        try {
            $booking = Booking::with([
                'user:id,name,email,phone',
                'lapangan:id,nama,lokasi,alamat,foto,harga_per_jam,jenis_olahraga,jam_buka,jam_tutup',
            ])->find($id);

            if (!$booking) {
                return $this->errorResponse('Booking tidak ditemukan.', null, 404);
            }

            // User hanya bisa lihat booking miliknya sendiri, admin bisa lihat semua
            $user = $request->user();
            if (!$user->isAdmin() && $booking->user_id !== $user->id) {
                return $this->errorResponse('Anda tidak memiliki akses ke booking ini.', null, 403);
            }

            return $this->successResponse('Detail booking berhasil diambil.', $this->formatBooking($booking));
        } catch (\Exception $e) {
            return $this->errorResponse('Terjadi kesalahan server: ' . $e->getMessage(), null, 500);
        }
    }

    // =============================================
    // CANCEL - Batalkan booking (oleh customer)
    // =============================================

    /**
     * Batalkan booking (hanya jika status pending, oleh owner booking)
     *
     * @param Request $request
     * @param int     $id
     * @return JsonResponse
     */
    public function cancel(Request $request, int $id): JsonResponse
    {
        try {
            $booking = Booking::find($id);

            if (!$booking) {
                return $this->errorResponse('Booking tidak ditemukan.', null, 404);
            }

            // Cek kepemilikan booking
            if ($booking->user_id !== $request->user()->id && !$request->user()->isAdmin()) {
                return $this->errorResponse('Anda tidak memiliki izin untuk membatalkan booking ini.', null, 403);
            }

            // Hanya booking dengan status pending yang bisa dibatalkan
            if (!$booking->bisaDibatalkan()) {
                return $this->errorResponse(
                    "Booking dengan status '{$booking->status}' tidak bisa dibatalkan. Hanya booking berstatus 'pending' yang bisa dibatalkan.",
                    null,
                    400
                );
            }

            $booking->update(['status' => 'cancelled']);

            return $this->successResponse('Booking berhasil dibatalkan.', [
                'id'           => $booking->id,
                'kode_booking' => $booking->kode_booking,
                'status'       => $booking->status,
            ]);
        } catch (\Exception $e) {
            return $this->errorResponse('Terjadi kesalahan server: ' . $e->getMessage(), null, 500);
        }
    }

    // =============================================
    // ALL BOOKINGS - Semua booking (admin)
    // =============================================

    /**
     * Ambil semua booking (hanya admin)
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function allBookings(Request $request): JsonResponse
    {
        try {
            $query = Booking::with([
                'user:id,name,email,phone',
                'lapangan:id,nama,lokasi,foto,jenis_olahraga',
            ])->orderByDesc('created_at');

            // Filter berdasarkan status
            if ($request->filled('status')) {
                $query->where('status', $request->status);
            }

            // Filter berdasarkan tanggal
            if ($request->filled('tanggal')) {
                $query->whereDate('tanggal', $request->tanggal);
            }

            // Filter berdasarkan lapangan
            if ($request->filled('lapangan_id')) {
                $query->where('lapangan_id', $request->lapangan_id);
            }

            // Filter berdasarkan user
            if ($request->filled('user_id')) {
                $query->where('user_id', $request->user_id);
            }

            $perPage  = min((int) $request->get('per_page', 15), 100);
            $bookings = $query->paginate($perPage);

            return $this->successResponse('Semua data booking berhasil diambil.', [
                'items'        => $bookings->map(fn($b) => $this->formatBooking($b)),
                'current_page' => $bookings->currentPage(),
                'last_page'    => $bookings->lastPage(),
                'per_page'     => $bookings->perPage(),
                'total'        => $bookings->total(),
            ]);
        } catch (\Exception $e) {
            return $this->errorResponse('Terjadi kesalahan server: ' . $e->getMessage(), null, 500);
        }
    }

    // =============================================
    // CONFIRM - Konfirmasi booking (admin)
    // =============================================

    /**
     * Konfirmasi booking (hanya admin)
     *
     * @param int $id
     * @return JsonResponse
     */
    public function confirm(int $id): JsonResponse
    {
        try {
            $booking = Booking::find($id);

            if (!$booking) {
                return $this->errorResponse('Booking tidak ditemukan.', null, 404);
            }

            if (!$booking->bisaDikonfirmasi()) {
                return $this->errorResponse(
                    "Booking dengan status '{$booking->status}' tidak bisa dikonfirmasi.",
                    null,
                    400
                );
            }

            $booking->update(['status' => 'confirmed']);

            return $this->successResponse('Booking berhasil dikonfirmasi.', [
                'id'           => $booking->id,
                'kode_booking' => $booking->kode_booking,
                'status'       => $booking->status,
            ]);
        } catch (\Exception $e) {
            return $this->errorResponse('Terjadi kesalahan server: ' . $e->getMessage(), null, 500);
        }
    }

    // =============================================
    // REJECT - Tolak booking (admin)
    // =============================================

    /**
     * Tolak booking dengan alasan (hanya admin)
     *
     * @param Request $request
     * @param int     $id
     * @return JsonResponse
     */
    public function reject(Request $request, int $id): JsonResponse
    {
        try {
            $booking = Booking::find($id);

            if (!$booking) {
                return $this->errorResponse('Booking tidak ditemukan.', null, 404);
            }

            if (!$booking->bisaDitolak()) {
                return $this->errorResponse(
                    "Booking dengan status '{$booking->status}' tidak bisa ditolak.",
                    null,
                    400
                );
            }

            // Validasi alasan penolakan
            $validator = Validator::make($request->all(), [
                'alasan_penolakan' => 'required|string|max:500',
            ], [
                'alasan_penolakan.required' => 'Alasan penolakan wajib diisi.',
                'alasan_penolakan.max'      => 'Alasan penolakan maksimal 500 karakter.',
            ]);

            if ($validator->fails()) {
                return $this->errorResponse('Validasi gagal.', $validator->errors(), 422);
            }

            $booking->update([
                'status'            => 'rejected',
                'alasan_penolakan'  => $request->alasan_penolakan,
            ]);

            return $this->successResponse('Booking berhasil ditolak.', [
                'id'                => $booking->id,
                'kode_booking'      => $booking->kode_booking,
                'status'            => $booking->status,
                'alasan_penolakan'  => $booking->alasan_penolakan,
            ]);
        } catch (\Exception $e) {
            return $this->errorResponse('Terjadi kesalahan server: ' . $e->getMessage(), null, 500);
        }
    }

    // =============================================
    // UPDATE STATUS - Update status booking (admin)
    // =============================================

    /**
     * Update status booking secara manual (hanya admin)
     *
     * @param Request $request
     * @param int     $id
     * @return JsonResponse
     */
    public function updateStatus(Request $request, int $id): JsonResponse
    {
        try {
            $booking = Booking::find($id);

            if (!$booking) {
                return $this->errorResponse('Booking tidak ditemukan.', null, 404);
            }

            // Validasi status
            $validator = Validator::make($request->all(), [
                'status'            => 'required|in:pending,confirmed,cancelled,completed,rejected',
                'alasan_penolakan'  => 'required_if:status,rejected|nullable|string|max:500',
            ], [
                'status.required'           => 'Status wajib diisi.',
                'status.in'                 => 'Status tidak valid.',
                'alasan_penolakan.required_if' => 'Alasan penolakan wajib diisi jika status ditolak.',
            ]);

            if ($validator->fails()) {
                return $this->errorResponse('Validasi gagal.', $validator->errors(), 422);
            }

            $updateData = ['status' => $request->status];

            if ($request->status === 'rejected') {
                $updateData['alasan_penolakan'] = $request->alasan_penolakan;
            }

            $booking->update($updateData);

            return $this->successResponse('Status booking berhasil diperbarui.', [
                'id'                => $booking->id,
                'kode_booking'      => $booking->kode_booking,
                'status'            => $booking->status,
                'alasan_penolakan'  => $booking->alasan_penolakan,
            ]);
        } catch (\Exception $e) {
            return $this->errorResponse('Terjadi kesalahan server: ' . $e->getMessage(), null, 500);
        }
    }

    // =============================================
    // HELPER: Format data booking
    // =============================================

    /**
     * Format data booking untuk response API
     */
    private function formatBooking(Booking $booking): array
    {
        $data = [
            'id'                => $booking->id,
            'kode_booking'      => $booking->kode_booking,
            'tanggal'           => $booking->tanggal?->toDateString(),
            'jam_mulai'         => $booking->jam_mulai,
            'jam_selesai'       => $booking->jam_selesai,
            'durasi_jam'        => $booking->durasi_jam,
            'total_harga'       => $booking->total_harga,
            'status'            => $booking->status,
            'catatan'           => $booking->catatan,
            'alasan_penolakan'  => $booking->alasan_penolakan,
            'created_at'        => $booking->created_at?->toDateTimeString(),
            'updated_at'        => $booking->updated_at?->toDateTimeString(),
        ];

        // Tambahkan data user jika sudah di-load
        if ($booking->relationLoaded('user') && $booking->user) {
            $data['user'] = [
                'id'    => $booking->user->id,
                'name'  => $booking->user->name,
                'email' => $booking->user->email,
                'phone' => $booking->user->phone,
            ];
        }

        // Tambahkan data lapangan jika sudah di-load
        if ($booking->relationLoaded('lapangan') && $booking->lapangan) {
            $data['lapangan'] = [
                'id'             => $booking->lapangan->id,
                'nama'           => $booking->lapangan->nama,
                'lokasi'         => $booking->lapangan->lokasi,
                'alamat'         => $booking->lapangan->alamat ?? null,
                'foto'           => $booking->lapangan->foto,
                'harga_per_jam'  => $booking->lapangan->harga_per_jam,
                'jenis_olahraga' => $booking->lapangan->jenis_olahraga,
            ];
        }

        return $data;
    }
}
