<?php

namespace App\Http\Controllers;

use App\Models\Appointment;
use App\Models\Barber;
use App\Models\Service;
use App\Notifications\AppointmentCreatedNotification;
use App\Services\AppointmentConflictService;
use App\Services\WhatsAppService;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;

class AdminAppointmentController extends Controller
{
    /**
     * Create appointment manually (admin).
     */
    public function store(Request $request)
    {
        $request->validate([
            'client_id' => 'required|exists:users,id',
            'barber_id' => 'required|exists:barbers,id',
            'service_id' => 'required|exists:services,id',
            'appointment_date' => 'required|date',
            'start_time' => 'required|date_format:H:i',
        ]);

        $service = Service::findOrFail($request->service_id);
        $dateStr = $request->appointment_date;
        $start = Carbon::parse($dateStr.' '.$request->start_time);
        $end = $start->copy()->addMinutes($service->duration_minutes);
        $endTime = $end->format('H:i');

        $appointment = DB::transaction(function () use ($request, $dateStr, $start, $end, $endTime) {
            app(AppointmentConflictService::class)->assertBarberIntervalAvailable(
                (int) $request->barber_id,
                $dateStr,
                $start,
                $end,
                null
            );

            return Appointment::create([
                'client_id' => $request->client_id,
                'barber_id' => $request->barber_id,
                'service_id' => $request->service_id,
                'appointment_date' => $request->appointment_date,
                'start_time' => $request->start_time,
                'end_time' => $endTime,
                'status' => 'confirmed',
            ]);
        });

        $appointment->load(['client', 'barber.user', 'service']);

        $appointment->client->notify(new AppointmentCreatedNotification($appointment, 'client'));
        $appointment->barber->user->notify(new AppointmentCreatedNotification($appointment, 'barber'));

        $whatsapp = app(WhatsAppService::class);
        if ($whatsapp->isConfigured() && $appointment->client?->phone) {
            $whatsapp->sendAppointmentConfirmation($appointment);
        }

        return response()->json($appointment, 201);
    }

    /**
     * Confirm a pending appointment (admin override).
     */
    public function confirm(Request $request, int $id)
    {
        $appointment = Appointment::findOrFail($id);

        if ($appointment->status !== 'pending') {
            return response()->json(['message' => 'Solo se pueden confirmar citas pendientes.'], 422);
        }

        $appointment->update(['status' => 'confirmed']);
        $appointment->load(['client', 'barber.user', 'service']);

        $whatsapp = app(WhatsAppService::class);
        if ($whatsapp->isConfigured() && $appointment->client?->phone) {
            $whatsapp->sendAppointmentConfirmation($appointment);
        }

        return response()->json($appointment);
    }

    /**
     * Cancel an appointment that is not already terminal (admin).
     */
    public function cancel(Request $request, int $id)
    {
        $appointment = Appointment::findOrFail($id);

        if (in_array($appointment->status, ['completed', 'cancelled'], true)) {
            return response()->json(['message' => 'La cita ya no se puede cancelar.'], 422);
        }

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

        return response()->json([
            'message' => 'Cita cancelada.',
            'appointment' => $appointment->load(['client', 'barber.user', 'service']),
        ]);
    }

    /**
     * Mark a pending or confirmed appointment as completed (admin).
     */
    public function complete(Request $request, int $id)
    {
        $appointment = Appointment::findOrFail($id);

        if (! in_array($appointment->status, ['pending', 'confirmed'], true)) {
            return response()->json(['message' => 'Solo citas pendientes o confirmadas pueden marcarse como completadas.'], 422);
        }

        $appointment->update(['status' => 'completed']);
        $appointment->load(['client', 'barber.user', 'service']);

        return response()->json($appointment);
    }

    /**
     * Reschedule / reassign an appointment (admin). Allowed unless cancelled.
     */
    public function update(Request $request, int $id)
    {
        $appointment = Appointment::findOrFail($id);

        $validated = $request->validate([
            'appointment_date' => 'required|date',
            'start_time' => 'required|date_format:H:i',
            'barber_id' => 'required|exists:barbers,id',
            'service_id' => 'required|exists:services,id',
        ]);

        $service = Service::findOrFail($validated['service_id']);
        $barber = Barber::findOrFail($validated['barber_id']);

        if (! $barber->services()->where('services.id', $service->id)->exists()) {
            return response()->json(['message' => 'El servicio no está asignado a ese profesional.'], 422);
        }

        $dateStr = $validated['appointment_date'];
        $start = Carbon::parse($dateStr.' '.$validated['start_time']);
        $end = $start->copy()->addMinutes($service->duration_minutes);
        $endTime = $end->format('H:i');

        DB::transaction(function () use ($appointment, $validated, $dateStr, $start, $end, $endTime) {
            app(AppointmentConflictService::class)->assertBarberIntervalAvailable(
                (int) $validated['barber_id'],
                $dateStr,
                $start,
                $end,
                $appointment->id
            );

            $appointment->update([
                'barber_id' => $validated['barber_id'],
                'service_id' => $validated['service_id'],
                'appointment_date' => $dateStr,
                'start_time' => $validated['start_time'],
                'end_time' => $endTime,
            ]);
        });

        return response()->json($appointment->fresh()->load(['client', 'barber.user', 'service']));
    }

    /**
     * Citas pendientes de confirmación (reservas web de clientes) — vista bandeja.
     */
    public function pendingInbox(Request $request)
    {
        $items = Appointment::with(['client', 'barber.user', 'service'])
            ->where('status', 'pending')
            ->orderBy('appointment_date')
            ->orderBy('start_time')
            ->limit(500)
            ->get();

        return response()->json($items);
    }

    /**
     * Confirmar varias o todas las citas pendientes.
     *
     * Body: { "ids": [1,2,3] } o { "all": true }
     */
    public function confirmBulk(Request $request)
    {
        if ($request->boolean('all')) {
            $count = DB::transaction(function () {
                return Appointment::where('status', 'pending')->update([
                    'status' => 'confirmed',
                    'updated_at' => now(),
                ]);
            });
        } else {
            $validated = $request->validate([
                'ids' => 'required|array|min:1',
                'ids.*' => 'integer|exists:appointments,id',
            ]);
            $ids = $validated['ids'];
            $count = DB::transaction(function () use ($ids) {
                return Appointment::whereIn('id', $ids)
                    ->where('status', 'pending')
                    ->update([
                        'status' => 'confirmed',
                        'updated_at' => now(),
                    ]);
            });
        }

        return response()->json([
            'message' => $count > 0
                ? "Se confirmaron {$count} cita(s)."
                : 'No había citas pendientes que coincidan.',
            'confirmed_count' => $count,
        ]);
    }

    /**
     * Forzar estado de la cita (incluye corregir citas completadas o canceladas).
     */
    public function setStatus(Request $request, int $id)
    {
        $validated = $request->validate([
            'status' => 'required|in:pending,confirmed,completed,cancelled',
        ]);

        $appointment = Appointment::findOrFail($id);
        $appointment->update(['status' => $validated['status']]);

        return response()->json($appointment->fresh()->load(['client', 'barber.user', 'service']));
    }

    /**
     * Eliminar cita y sus registros (y archivos de fotos). Solo admin.
     */
    public function destroy(int $id)
    {
        $appointment = Appointment::with('photos')->findOrFail($id);

        foreach ($appointment->photos as $photo) {
            if ($photo->file_path && Storage::disk('photos')->exists($photo->file_path)) {
                Storage::disk('photos')->delete($photo->file_path);
            }
        }

        $appointment->delete();

        return response()->json(['message' => 'Cita eliminada.']);
    }
}
