<?php

namespace App\Http\Controllers\Api;

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

class TimeSlotController 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);
    }

    // =============================================
    // INDEX - List slot berdasarkan lapangan
    // =============================================

    /**
     * Ambil semua time slot untuk lapangan tertentu
     *
     * @param Request $request
     * @param int     $lapanganId
     * @return JsonResponse
     */
    public function index(Request $request, int $lapanganId): JsonResponse
    {
        try {
            $lapangan = Lapangan::find($lapanganId);

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

            $query = TimeSlot::where('lapangan_id', $lapanganId)
                ->orderBy('jam_mulai');

            // Filter hanya yang tersedia
            if ($request->boolean('is_available')) {
                $query->where('is_available', true);
            }

            $slots = $query->get();

            return $this->successResponse('Data time slot berhasil diambil.', [
                'lapangan_id'   => $lapanganId,
                'nama_lapangan' => $lapangan->nama,
                'items'         => $slots->map(fn($s) => $this->formatSlot($s, $lapangan)),
                'total'         => $slots->count(),
            ]);
        } catch (\Exception $e) {
            return $this->errorResponse('Terjadi kesalahan server: ' . $e->getMessage(), null, 500);
        }
    }

    // =============================================
    // AVAILABLE - Slot yang tersedia untuk tanggal tertentu
    // =============================================

    /**
     * Ambil slot yang tersedia untuk lapangan dan tanggal tertentu
     * Cek booking yang sudah ada agar tidak bentrok
     *
     * @param Request $request
     * @param int     $lapanganId
     * @return JsonResponse
     */
    public function available(Request $request, int $lapanganId): JsonResponse
    {
        try {
            $lapangan = Lapangan::find($lapanganId);

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

            // Validasi tanggal wajib ada
            $validator = Validator::make($request->all(), [
                'tanggal' => 'required|date|date_format:Y-m-d|after_or_equal:today',
            ], [
                'tanggal.required'       => 'Tanggal wajib diisi.',
                'tanggal.date_format'    => 'Format tanggal harus Y-m-d (contoh: 2024-01-15).',
                'tanggal.after_or_equal' => 'Tanggal tidak boleh di masa lalu.',
            ]);

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

            $tanggal = $request->tanggal;

            // Ambil semua slot yang is_available = true untuk lapangan ini
            $allSlots = TimeSlot::where('lapangan_id', $lapanganId)
                ->where('is_available', true)
                ->orderBy('jam_mulai')
                ->get();

            // Ambil booking yang sudah ada untuk tanggal ini (status pending/confirmed)
            $existingBookings = Booking::where('lapangan_id', $lapanganId)
                ->whereDate('tanggal', $tanggal)
                ->whereIn('status', ['pending', 'confirmed'])
                ->get(['jam_mulai', 'jam_selesai', 'kode_booking', 'status']);

            // Tandai slot yang sudah dipesan
            $slotsWithStatus = $allSlots->map(function ($slot) use ($existingBookings, $lapangan) {
                $conflictingBooking = $existingBookings->first(function ($booking) use ($slot) {
                    return $booking->jam_mulai < $slot->jam_selesai
                        && $booking->jam_selesai > $slot->jam_mulai;
                });

                return [
                    'id'           => $slot->id,
                    'jam_mulai'    => $slot->jam_mulai,
                    'jam_selesai'  => $slot->jam_selesai,
                    'harga'        => $slot->harga ?? $lapangan->harga_per_jam,
                    'is_available' => $conflictingBooking === null,
                    'is_booked'    => $conflictingBooking !== null,
                    'kode_booking' => $conflictingBooking?->kode_booking ?? null,
                ];
            });

            // Pisahkan slot tersedia dan tidak tersedia
            $availableCount = $slotsWithStatus->where('is_available', true)->count();
            $bookedCount    = $slotsWithStatus->where('is_booked', true)->count();

            return $this->successResponse('Slot tersedia berhasil diambil.', [
                'lapangan_id'     => $lapanganId,
                'nama_lapangan'   => $lapangan->nama,
                'tanggal'         => $tanggal,
                'total_slot'      => $slotsWithStatus->count(),
                'tersedia'        => $availableCount,
                'sudah_dipesan'   => $bookedCount,
                'slots'           => $slotsWithStatus->values(),
            ]);
        } catch (\Exception $e) {
            return $this->errorResponse('Terjadi kesalahan server: ' . $e->getMessage(), null, 500);
        }
    }

    // =============================================
    // STORE - Buat slot baru (admin)
    // =============================================

    /**
     * Buat time slot baru untuk lapangan (hanya admin)
     *
     * @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',
                'jam_mulai'    => 'required|date_format:H:i',
                'jam_selesai'  => 'required|date_format:H:i|after:jam_mulai',
                'is_available' => 'boolean',
                'harga'        => 'nullable|integer|min:0',
            ], [
                'lapangan_id.required'  => 'Lapangan wajib dipilih.',
                'lapangan_id.exists'    => 'Lapangan tidak ditemukan.',
                'jam_mulai.required'    => 'Jam mulai wajib diisi.',
                'jam_selesai.required'  => 'Jam selesai wajib diisi.',
                'jam_selesai.after'     => 'Jam selesai harus setelah jam mulai.',
                'harga.min'             => 'Harga tidak boleh negatif.',
            ]);

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

            // Cek apakah slot sudah ada (duplikasi)
            $exists = TimeSlot::where('lapangan_id', $request->lapangan_id)
                ->where('jam_mulai', $request->jam_mulai . ':00')
                ->where('jam_selesai', $request->jam_selesai . ':00')
                ->exists();

            if ($exists) {
                return $this->errorResponse(
                    "Slot {$request->jam_mulai} - {$request->jam_selesai} sudah ada untuk lapangan ini.",
                    null,
                    409
                );
            }

            $lapangan = Lapangan::find($request->lapangan_id);

            // Cek apakah dalam jam operasional lapangan
            $jamBuka   = $lapangan->jam_buka;
            $jamTutup  = $lapangan->jam_tutup;
            $jamMulai  = $request->jam_mulai . ':00';
            $jamSelesai = $request->jam_selesai . ':00';

            if ($jamMulai < $jamBuka || $jamSelesai > $jamTutup) {
                return $this->errorResponse(
                    "Slot waktu di luar jam operasional lapangan ({$jamBuka} - {$jamTutup}).",
                    null,
                    400
                );
            }

            $slot = TimeSlot::create([
                'lapangan_id'  => $request->lapangan_id,
                'jam_mulai'    => $jamMulai,
                'jam_selesai'  => $jamSelesai,
                'is_available' => $request->boolean('is_available', true),
                'harga'        => $request->harga,
            ]);

            return $this->successResponse(
                'Time slot berhasil dibuat.',
                $this->formatSlot($slot, $lapangan),
                201
            );
        } catch (\Exception $e) {
            return $this->errorResponse('Terjadi kesalahan server: ' . $e->getMessage(), null, 500);
        }
    }

    // =============================================
    // UPDATE - Edit slot (admin)
    // =============================================

    /**
     * Update time slot (hanya admin)
     *
     * @param Request $request
     * @param int     $id
     * @return JsonResponse
     */
    public function update(Request $request, int $id): JsonResponse
    {
        try {
            $slot = TimeSlot::with('lapangan')->find($id);

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

            // Validasi input
            $validator = Validator::make($request->all(), [
                'jam_mulai'    => 'sometimes|date_format:H:i',
                'jam_selesai'  => 'sometimes|date_format:H:i',
                'is_available' => 'sometimes|boolean',
                'harga'        => 'nullable|integer|min:0',
            ], [
                'harga.min' => 'Harga tidak boleh negatif.',
            ]);

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

            $updateData = [];

            if ($request->has('jam_mulai')) {
                $updateData['jam_mulai'] = $request->jam_mulai . ':00';
            }
            if ($request->has('jam_selesai')) {
                $updateData['jam_selesai'] = $request->jam_selesai . ':00';
            }
            if ($request->has('is_available')) {
                $updateData['is_available'] = $request->boolean('is_available');
            }
            if ($request->has('harga')) {
                $updateData['harga'] = $request->harga;
            }

            $slot->update($updateData);

            return $this->successResponse(
                'Time slot berhasil diperbarui.',
                $this->formatSlot($slot->fresh(), $slot->lapangan)
            );
        } catch (\Exception $e) {
            return $this->errorResponse('Terjadi kesalahan server: ' . $e->getMessage(), null, 500);
        }
    }

    // =============================================
    // DESTROY - Hapus slot (admin)
    // =============================================

    /**
     * Hapus time slot (hanya admin)
     *
     * @param int $id
     * @return JsonResponse
     */
    public function destroy(int $id): JsonResponse
    {
        try {
            $slot = TimeSlot::find($id);

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

            $slot->delete();

            return $this->successResponse('Time slot berhasil dihapus.');
        } catch (\Exception $e) {
            return $this->errorResponse('Terjadi kesalahan server: ' . $e->getMessage(), null, 500);
        }
    }

    // =============================================
    // HELPER: Format data time slot
    // =============================================

    /**
     * Format data time slot untuk response API
     */
    private function formatSlot(TimeSlot $slot, ?Lapangan $lapangan = null): array
    {
        return [
            'id'           => $slot->id,
            'lapangan_id'  => $slot->lapangan_id,
            'jam_mulai'    => $slot->jam_mulai,
            'jam_selesai'  => $slot->jam_selesai,
            'is_available' => $slot->is_available,
            'harga'        => $slot->harga ?? ($lapangan?->harga_per_jam ?? null),
            'harga_asli'   => $slot->harga, // null = ikuti harga lapangan
            'created_at'   => $slot->created_at?->toDateTimeString(),
        ];
    }
}
