<?php

namespace App\Http\Controllers;

use App\Models\Appointment;
use App\Models\Order;
use App\Models\AuditLog;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\DB;

class AppointmentController extends Controller
{
    /**
     * Display a listing of the authenticated user's appointments
     */
    public function index(Request $request)
    {
        try {
            $user = auth()->user();
            
            $query = Appointment::with(['order', 'customer', 'assignedTechnician'])
                ->byCustomer($user->id);

            // Filter by status
            if ($request->has('status') && $request->status) {
                $query->where('status', $request->status);
            }

            // Sort by service date (upcoming first)
            $query->orderBy('service_date', 'asc')
                  ->orderBy('service_time', 'asc');

            // Pagination
            $perPage = $request->get('per_page', 10);
            $appointments = $query->paginate($perPage);

            return response()->json([
                'success' => true,
                'message' => 'Appointments retrieved successfully',
                'data' => [
                    'appointments' => $appointments->items(),
                    'pagination' => [
                        'current_page' => $appointments->currentPage(),
                        'per_page' => $appointments->perPage(),
                        'total' => $appointments->total(),
                        'last_page' => $appointments->lastPage(),
                    ]
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve appointments',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Display upcoming appointments for authenticated user
     */
    public function upcoming(Request $request)
    {
        try {
            $user = auth()->user();
            
            $appointments = Appointment::with(['order', 'assignedTechnician'])
                ->byCustomer($user->id)
                ->upcoming()
                ->orderBy('service_date', 'asc')
                ->orderBy('service_time', 'asc')
                ->limit(5)
                ->get();

            return response()->json([
                'success' => true,
                'message' => 'Upcoming appointments retrieved successfully',
                'data' => [
                    'appointments' => $appointments
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve upcoming appointments',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Display the specified appointment
     */
    public function show($id)
    {
        try {
            $user = auth()->user();
            
            $appointment = Appointment::with([
                'order.items.product', 
                'customer', 
                'assignedTechnician'
            ])->find($id);

            if (!$appointment) {
                return response()->json([
                    'success' => false,
                    'message' => 'Appointment not found'
                ], 404);
            }

            // Check if user owns the appointment or is admin
            if ($appointment->customer_id != $user->id && !$user->isAdmin()) {
                return response()->json([
                    'success' => false,
                    'message' => 'Unauthorized to view this appointment'
                ], 403);
            }

            return response()->json([
                'success' => true,
                'message' => 'Appointment retrieved successfully',
                'data' => [
                    'appointment' => $appointment
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve appointment',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Reschedule an appointment
     */
    public function reschedule(Request $request, $id)
    {
        $validator = Validator::make($request->all(), [
            'service_date' => 'required|date|after_or_equal:today',
            'service_time' => 'required|date_format:H:i',
            'reason' => 'nullable|string|max:500',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $validator->errors()
            ], 422);
        }

        try {
            $user = auth()->user();
            $appointment = Appointment::find($id);

            if (!$appointment) {
                return response()->json([
                    'success' => false,
                    'message' => 'Appointment not found'
                ], 404);
            }

            // Check if user owns the appointment
            if ($appointment->customer_id != $user->id) {
                return response()->json([
                    'success' => false,
                    'message' => 'Unauthorized to reschedule this appointment'
                ], 403);
            }

            // Check if appointment can be rescheduled
            if (!in_array($appointment->status, ['scheduled', 'confirmed'])) {
                return response()->json([
                    'success' => false,
                    'message' => 'Appointment cannot be rescheduled in its current status'
                ], 422);
            }

            $oldDate = $appointment->service_date;
            $oldTime = $appointment->service_time;

            $appointment->update([
                'service_date' => $request->service_date,
                'service_time' => $request->service_time,
                'status' => 'scheduled', // Reset to scheduled when rescheduled
                'notes' => $appointment->notes . "\nRescheduled from {$oldDate} {$oldTime}. Reason: " . ($request->reason ?? 'Not specified'),
            ]);

            // Log the rescheduling
            AuditLog::log($user, 'reschedule', $appointment, 
                ['service_date' => $oldDate, 'service_time' => $oldTime], 
                ['service_date' => $request->service_date, 'service_time' => $request->service_time], 
                request()
            );

            return response()->json([
                'success' => true,
                'message' => 'Appointment rescheduled successfully',
                'data' => [
                    'appointment' => $appointment->load(['order', 'assignedTechnician'])
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to reschedule appointment',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Cancel an appointment
     */
    public function cancel(Request $request, $id)
    {
        $validator = Validator::make($request->all(), [
            'cancellation_reason' => 'required|string|max:500',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $validator->errors()
            ], 422);
        }

        try {
            $user = auth()->user();
            $appointment = Appointment::with(['order'])->find($id);

            if (!$appointment) {
                return response()->json([
                    'success' => false,
                    'message' => 'Appointment not found'
                ], 404);
            }

            // Check if user owns the appointment
            if ($appointment->customer_id != $user->id) {
                return response()->json([
                    'success' => false,
                    'message' => 'Unauthorized to cancel this appointment'
                ], 403);
            }

            // Check if appointment can be cancelled
            if (!in_array($appointment->status, ['scheduled', 'confirmed'])) {
                return response()->json([
                    'success' => false,
                    'message' => 'Appointment cannot be cancelled in its current status'
                ], 422);
            }

            $appointment->update([
                'status' => 'cancelled',
                'cancelled_at' => now(),
                'cancellation_reason' => $request->cancellation_reason,
            ]);

            // Update order status if exists
            if ($appointment->order) {
                $appointment->order->update([
                    'status' => 'cancelled',
                    'cancelled_at' => now(),
                ]);
            }

            // Log the cancellation
            AuditLog::log($user, 'cancel', $appointment, null, [
                'status' => 'cancelled',
                'cancellation_reason' => $request->cancellation_reason
            ], request());

            return response()->json([
                'success' => true,
                'message' => 'Appointment cancelled successfully',
                'data' => [
                    'appointment' => $appointment->load(['order'])
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to cancel appointment',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Display a listing of all appointments (admin only)
     */
    public function adminIndex(Request $request)
    {
        try {
            $query = Appointment::with(['order', 'customer', 'assignedTechnician']);

            // Filter by status
            if ($request->has('status') && $request->status) {
                $query->where('status', $request->status);
            }

            // Filter by technician
            if ($request->has('technician_id') && $request->technician_id) {
                $query->where('assigned_to', $request->technician_id);
            }

            // Filter by date range
            if ($request->has('start_date') && $request->has('end_date')) {
                $query->byDateRange($request->start_date, $request->end_date);
            }

            // Filter by today
            if ($request->has('today') && $request->today) {
                $query->today();
            }

            // Search by customer name or order number
            if ($request->has('search') && $request->search) {
                $query->where(function($q) use ($request) {
                    $q->whereHas('customer', function($q2) use ($request) {
                        $q2->where('name', 'like', '%' . $request->search . '%')
                           ->orWhere('email', 'like', '%' . $request->search . '%')
                           ->orWhere('phone', 'like', '%' . $request->search . '%');
                    })->orWhereHas('order', function($q2) use ($request) {
                        $q2->where('order_number', 'like', '%' . $request->search . '%');
                    });
                });
            }

            // Sort options
            $sortBy = $request->get('sort_by', 'service_date');
            $sortOrder = $request->get('sort_order', 'asc');
            $query->orderBy($sortBy, $sortOrder)
                  ->orderBy('service_time', 'asc');

            // Pagination
            $perPage = $request->get('per_page', 15);
            $appointments = $query->paginate($perPage);

            return response()->json([
                'success' => true,
                'message' => 'Appointments retrieved successfully',
                'data' => [
                    'appointments' => $appointments->items(),
                    'pagination' => [
                        'current_page' => $appointments->currentPage(),
                        'per_page' => $appointments->perPage(),
                        'total' => $appointments->total(),
                        'last_page' => $appointments->lastPage(),
                    ]
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve appointments',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Assign technician to appointment (admin only)
     */
    public function assignTechnician(Request $request, $id)
    {
        $validator = Validator::make($request->all(), [
            'technician_id' => 'required|exists:users,id',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $validator->errors()
            ], 422);
        }

        try {
            $user = auth()->user();
            $appointment = Appointment::find($id);

            if (!$appointment) {
                return response()->json([
                    'success' => false,
                    'message' => 'Appointment not found'
                ], 404);
            }

            $oldTechnician = $appointment->assigned_to;
            $appointment->update(['assigned_to' => $request->technician_id]);

            // Log the assignment
            AuditLog::log($user, 'assign_technician', $appointment, 
                ['assigned_to' => $oldTechnician], 
                ['assigned_to' => $request->technician_id], 
                request()
            );

            return response()->json([
                'success' => true,
                'message' => 'Technician assigned successfully',
                'data' => [
                    'appointment' => $appointment->load(['assignedTechnician'])
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to assign technician',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Update appointment status (admin only)
     */
    public function updateStatus(Request $request, $id)
    {
        $validator = Validator::make($request->all(), [
            'status' => 'required|in:scheduled,confirmed,in_progress,completed,cancelled',
            'notes' => 'nullable|string',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $validator->errors()
            ], 422);
        }

        try {
            $user = auth()->user();
            $appointment = Appointment::with(['order'])->find($id);

            if (!$appointment) {
                return response()->json([
                    'success' => false,
                    'message' => 'Appointment not found'
                ], 404);
            }

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

            // Update completed_at if status is completed
            if ($request->status === 'completed') {
                $updateData['completed_at'] = now();
            }

            // Update notes if provided
            if ($request->has('notes')) {
                $updateData['notes'] = $appointment->notes . "\n" . now()->format('Y-m-d H:i') . ": " . $request->notes;
            }

            $appointment->update($updateData);

            // Update order status if exists
            if ($appointment->order && in_array($request->status, ['completed', 'cancelled'])) {
                $appointment->order->update(['status' => $request->status]);
            }

            // Log the status update
            AuditLog::log($user, 'status_update', $appointment, 
                ['status' => $oldStatus], 
                ['status' => $request->status], 
                request()
            );

            return response()->json([
                'success' => true,
                'message' => 'Appointment status updated successfully',
                'data' => [
                    'appointment' => $appointment->load(['order', 'assignedTechnician'])
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to update appointment status',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Generate appointment report (admin only)
     */
    public function appointmentReport(Request $request)
    {
        try {
            $startDate = $request->get('start_date', now()->subMonth()->format('Y-m-d'));
            $endDate = $request->get('end_date', now()->format('Y-m-d'));

            $report = DB::table('appointments')
                ->select(
                    DB::raw('COUNT(*) as total_appointments'),
                    DB::raw('COUNT(CASE WHEN status = "completed" THEN 1 END) as completed_appointments'),
                    DB::raw('COUNT(CASE WHEN status = "cancelled" THEN 1 END) as cancelled_appointments'),
                    DB::raw('COUNT(CASE WHEN status = "scheduled" THEN 1 END) as scheduled_appointments'),
                    DB::raw('COUNT(CASE WHEN status = "in_progress" THEN 1 END) as in_progress_appointments'),
                    DB::raw('AVG(duration) as average_duration')
                )
                ->whereBetween('service_date', [$startDate, $endDate])
                ->first();

            // Daily appointment trend
            $dailyTrend = DB::table('appointments')
                ->select(
                    DB::raw('DATE(service_date) as date'),
                    DB::raw('COUNT(*) as appointment_count'),
                    DB::raw('COUNT(CASE WHEN status = "completed" THEN 1 END) as completed_count')
                )
                ->whereBetween('service_date', [$startDate, $endDate])
                ->groupBy('date')
                ->orderBy('date')
                ->get();

            // Technician performance
            $technicianPerformance = DB::table('appointments')
                ->join('users', 'appointments.assigned_to', '=', 'users.id')
                ->select(
                    'users.name as technician_name',
                    DB::raw('COUNT(*) as total_appointments'),
                    DB::raw('COUNT(CASE WHEN status = "completed" THEN 1 END) as completed_appointments'),
                    DB::raw('AVG(duration) as average_duration')
                )
                ->whereBetween('service_date', [$startDate, $endDate])
                ->whereNotNull('assigned_to')
                ->groupBy('assigned_to', 'users.name')
                ->orderByDesc('completed_appointments')
                ->get();

            return response()->json([
                'success' => true,
                'message' => 'Appointment report generated successfully',
                'data' => [
                    'report_period' => [
                        'start_date' => $startDate,
                        'end_date' => $endDate,
                    ],
                    'summary' => $report,
                    'daily_trend' => $dailyTrend,
                    'technician_performance' => $technicianPerformance,
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to generate appointment report',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get today's appointments (admin only)
     */
    public function getTodayAppointments()
    {
        try {
            $appointments = Appointment::with(['order', 'customer', 'assignedTechnician'])
                ->today()
                ->whereIn('status', ['scheduled', 'confirmed', 'in_progress'])
                ->orderBy('service_time', 'asc')
                ->get();

            return response()->json([
                'success' => true,
                'message' => "Today's appointments retrieved successfully",
                'data' => [
                    'appointments' => $appointments
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => "Failed to retrieve today's appointments",
                'error' => $e->getMessage()
            ], 500);
    }
}

    /**
     * Store a newly created appointment
     */
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'customer_name' => 'required|string|max:255',
            'customer_phone' => 'required|string|max:20',
            'customer_email' => 'nullable|email|max:255',
            'car_make' => 'required|string|max:100',
            'car_model' => 'required|string|max:100',
            'car_year' => 'required|integer|min:1900|max:' . (date('Y') + 1),
            'service_type' => 'required|string|max:255',
            'service_date' => 'required|date|after_or_equal:today',
            'service_time' => 'required|date_format:H:i',
            'county' => 'required|string|max:100',
            'subcounty' => 'required|string|max:100',
            'address' => 'required|string|max:500',
            'service_location' => 'required|in:workshop,on_site',
            'estimated_price' => 'required|numeric|min:0',
            'notes' => 'nullable|string|max:1000',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $validator->errors()
            ], 422);
        }

        try {
            $user = auth()->user();
            
            // Check for conflicting appointments
            $conflict = Appointment::where('service_date', $request->service_date)
                ->where('service_time', $request->service_time)
                ->whereIn('status', ['scheduled', 'confirmed'])
                ->exists();

            if ($conflict) {
                return response()->json([
                    'success' => false,
                    'message' => 'Time slot is already booked. Please choose a different time.'
                ], 409);
            }

            // Create appointment
            $appointment = Appointment::create([
                'customer_id' => $user->id,
                'customer_name' => $request->customer_name,
                'customer_phone' => $request->customer_phone,
                'customer_email' => $request->customer_email,
                'car_make' => $request->car_make,
                'car_model' => $request->car_model,
                'car_year' => $request->car_year,
                'service_type' => $request->service_type,
                'service_date' => $request->service_date,
                'service_time' => $request->service_time,
                'status' => 'scheduled',
                'notes' => $request->notes,
                'county' => $request->county,
                'subcounty' => $request->subcounty,
                'address' => $request->address,
                'service_location' => $request->service_location,
                'estimated_price' => $request->estimated_price,
                'payment_status' => 'pending',
            ]);

            // Log the creation
            AuditLog::logCreate($user, $appointment, $request);

            return response()->json([
                'success' => true,
                'message' => 'Appointment booked successfully',
                'data' => [
                    'appointment' => $appointment->load(['customer', 'assignedTechnician'])
                ]
            ], 201);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to create appointment',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get available time slots for a specific date
     */
    public function getAvailableTimeSlots(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'date' => 'required|date|after_or_equal:today',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $validator->errors()
            ], 422);
        }

        try {
            $date = $request->date;
            
            // Get booked time slots for the date
            $bookedSlots = Appointment::where('service_date', $date)
                ->whereIn('status', ['scheduled', 'confirmed'])
                ->pluck('service_time')
                ->toArray();

            // Define available time slots (8:00 AM to 5:00 PM in 30-minute intervals)
            $allSlots = [
                '08:00', '08:30', '09:00', '09:30', '10:00', '10:30',
                '11:00', '11:30', '12:00', '12:30', '13:00', '13:30',
                '14:00', '14:30', '15:00', '15:30', '16:00', '16:30', '17:00'
            ];

            // Filter out booked slots
            $availableSlots = array_diff($allSlots, $bookedSlots);

            return response()->json([
                'success' => true,
                'message' => 'Available time slots retrieved successfully',
                'data' => [
                    'available_slots' => array_values($availableSlots),
                    'date' => $date
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve available time slots',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get appointments needing reminders (admin only)
     */
    public function getAppointmentsNeedingReminders()
    {
        try {
            $appointments = Appointment::with(['order', 'customer'])
                ->whereIn('status', ['scheduled', 'confirmed'])
                ->where('service_date', '>=', now()->toDateString())
                ->where('reminder_sent', false)
                ->get()
                ->filter(function($appointment) {
                    return $appointment->needsReminder();
                })
                ->values();

            return response()->json([
                'success' => true,
                'message' => 'Appointments needing reminders retrieved successfully',
                'data' => [
                    'appointments' => $appointments
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve appointments needing reminders',
                'error' => $e->getMessage()
            ], 500);
        }
    }
}