<?php

namespace App\Http\Controllers;

use App\Models\Appointment;
use App\Models\Branch;
use App\Models\Customer;
use App\Models\Service;
use App\Services\AppointmentService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class AppointmentController extends Controller
{
    public function __construct(
        protected AppointmentService $appointmentService
    ) {
    }

    public function index(Request $request): View
    {
        $branchId = $request->user()?->branch_id;
        $appointments = $this->appointmentService->paginate(
            $request->only(['search', 'branch_id', 'status', 'date', 'date_from', 'date_to']),
            $branchId,
            15
        );
        $branches = Branch::where('status', 'active')->orderBy('name')->get();
        return view('appointments.index', compact('appointments', 'branches'));
    }

    public function create(): View
    {
        $branchId = request()->user()?->branch_id;
        $branches = Branch::where('status', 'active')->orderBy('name')->get();
        $customers = $branchId
            ? Customer::where('branch_id', $branchId)->where('status', 'active')->orderBy('full_name')->get()
            : Customer::where('status', 'active')->orderBy('full_name')->get();
        $services = Service::where('status', 'active')->with('category')->orderBy('name')->get();
        $staff = \App\Models\StaffProfile::where('status', 'active')
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->orderBy('full_name')->get();
        return view('appointments.create', compact('branches', 'customers', 'services', 'staff', 'branchId'));
    }

    public function store(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'branch_id' => 'required|exists:branches,id',
            'customer_id' => 'nullable|exists:customers,id',
            'appointment_date' => 'required|date',
            'start_time' => 'required|string',
            'services' => 'required|array|min:1',
            'services.*.service_id' => 'required|exists:services,id',
            'services.*.assigned_staff_id' => 'nullable|exists:staff_profiles,id',
            'booking_source' => 'nullable|string|in:admin,reception,walk-in,online',
            'status' => 'nullable|string|in:pending,confirmed',
            'notes' => 'nullable|string',
        ]);
        $items = [];
        foreach ($validated['services'] as $s) {
            $service = Service::find($s['service_id']);
            $items[] = [
                'service_id' => $service->id,
                'assigned_staff_id' => $s['assigned_staff_id'] ?? null,
                'price' => $service->price,
                'duration_minutes' => $service->duration_minutes,
                'buffer_minutes' => $service->buffer_minutes,
            ];
        }
        $validated['services'] = $items;
        $this->appointmentService->create($validated);
        return redirect()->route('appointments.index')->with('success', 'Appointment created successfully.');
    }

    public function show(Appointment $appointment): View
    {
        $appointment->load(['branch', 'customer', 'appointmentServices.service', 'appointmentServices.assignedStaff']);
        return view('appointments.show', compact('appointment'));
    }

    public function edit(Appointment $appointment): View
    {
        $branchId = request()->user()?->branch_id;
        $branches = Branch::where('status', 'active')->orderBy('name')->get();
        $customers = $branchId ? Customer::where('branch_id', $branchId)->where('status', 'active')->orderBy('full_name')->get() : Customer::where('status', 'active')->orderBy('full_name')->get();
        $services = Service::where('status', 'active')->with('category')->orderBy('name')->get();
        $staff = \App\Models\StaffProfile::where('status', 'active')->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->orderBy('full_name')->get();
        $appointment->load('appointmentServices');
        return view('appointments.edit', compact('appointment', 'branches', 'customers', 'services', 'staff', 'branchId'));
    }

    public function update(Request $request, Appointment $appointment): RedirectResponse
    {
        $validated = $request->validate([
            'appointment_date' => 'required|date',
            'start_time' => 'required|string',
            'services' => 'required|array|min:1',
            'services.*.service_id' => 'required|exists:services,id',
            'services.*.assigned_staff_id' => 'nullable|exists:staff_profiles,id',
            'notes' => 'nullable|string',
        ]);
        $items = [];
        foreach ($validated['services'] as $s) {
            $service = Service::find($s['service_id']);
            $items[] = [
                'service_id' => $service->id,
                'assigned_staff_id' => $s['assigned_staff_id'] ?? null,
                'price' => $service->price,
                'duration_minutes' => $service->duration_minutes,
                'buffer_minutes' => $service->buffer_minutes,
            ];
        }
        $validated['services'] = $items;
        $this->appointmentService->update($appointment, $validated);
        return redirect()->route('appointments.index')->with('success', 'Appointment updated successfully.');
    }

    public function destroy(Appointment $appointment): RedirectResponse
    {
        $appointment->delete();
        return redirect()->route('appointments.index')->with('success', 'Appointment deleted.');
    }

    public function calendar(Request $request): View
    {
        $branchId = $request->get('branch_id', $request->user()?->branch_id);
        $date = $request->get('date', now()->toDateString());
        $branches = Branch::where('status', 'active')->orderBy('name')->get();
        $appointments = Appointment::query()
            ->with(['branch', 'customer', 'appointmentServices.service', 'appointmentServices.assignedStaff'])
            ->where('appointment_date', $date)
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->orderBy('start_time')
            ->get();
        return view('appointments.calendar', compact('branchId', 'date', 'branches', 'appointments'));
    }

    public function checkIn(Appointment $appointment): RedirectResponse
    {
        $this->appointmentService->checkIn($appointment);
        return back()->with('success', 'Customer checked in.');
    }

    public function complete(Appointment $appointment): RedirectResponse
    {
        $this->appointmentService->complete($appointment);
        return back()->with('success', 'Appointment completed.');
    }

    public function cancel(Request $request, Appointment $appointment): RedirectResponse
    {
        $request->validate(['cancellation_reason' => 'required|string|max:500']);
        $this->appointmentService->cancel($appointment, $request->cancellation_reason);
        return back()->with('success', 'Appointment cancelled.');
    }

    public function noShow(Appointment $appointment): RedirectResponse
    {
        $this->appointmentService->markNoShow($appointment);
        return back()->with('success', 'Marked as no-show.');
    }
}
