<?php

namespace App\Http\Controllers;

use App\Models\Maintenance;
use App\Models\Room;
use App\Models\Staff;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use App\Http\Controllers\Concerns\ResolvesTenantHotel;
use Illuminate\Validation\Rule;

class MaintenanceController extends Controller
{
    use ResolvesTenantHotel;

    public function index(Request $request)
    {
        $hotelId = $this->tenantHotelIdOrAbort();
        $query = Maintenance::where('hotel_id', $hotelId)->with(['room', 'assignedTechnician', 'reportedBy']);
        
        // Search functionality
        if ($request->has('search') && $request->search != '') {
            $search = $request->search;
            $query->where(function($q) use ($search) {
                $q->where('title', 'like', "%{$search}%")
                  ->orWhere('description', 'like', "%{$search}%")
                  ->orWhere('location', 'like', "%{$search}%")
                  ->orWhereHas('room', function($q) use ($search) {
                      $q->where('room_number', 'like', "%{$search}%");
                  })
                  ->orWhereHas('assignedTechnician', function($q) use ($search) {
                      $q->where('first_name', 'like', "%{$search}%")
                        ->orWhere('last_name', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%")
                        ->orWhere('employee_id', 'like', "%{$search}%");
                  });
            });
        }
        
        // Filter by room
        if ($request->has('room_id') && $request->room_id != '') {
            $query->where('room_id', $request->room_id);
        }
        
        // Filter by status
        if ($request->has('status') && $request->status != '') {
            $query->where('status', $request->status);
        }
        
        // Filter by priority
        if ($request->has('priority') && $request->priority != '') {
            $query->where('priority', $request->priority);
        }
        
        // Filter by assigned technician
        if ($request->has('assigned_to') && $request->assigned_to != '') {
            $query->where('assigned_to', $request->assigned_to);
        }
        
        // Filter by maintenance type
        if ($request->has('maintenance_type') && $request->maintenance_type != '') {
            $query->where('maintenance_type', $request->maintenance_type);
        }
        
        // Filter by date range
        if ($request->has('date_from') && $request->date_from != '') {
            $query->whereDate('reported_date', '>=', $request->date_from);
        }
        
        if ($request->has('date_to') && $request->date_to != '') {
            $query->whereDate('reported_date', '<=', $request->date_to);
        }
        
        $maintenances = $query->orderBy('created_at', 'desc')->paginate(20);
        
        // Get data for filter dropdowns
        $rooms = Room::where('hotel_id', $hotelId)->orderBy('room_number')->get(['id', 'room_number']);
        
        // Get technicians from Staff table (active staff only)
        $technicians = Staff::where('hotel_id', $hotelId)->where('status', 'active')
            ->orderBy('first_name')
            ->orderBy('last_name')
            ->get(['id', 'first_name', 'last_name', 'email', 'employee_id']);
        
        // Statistics for dashboard
        $stats = [
            'total' => Maintenance::where('hotel_id', $hotelId)->count(),
            'pending' => Maintenance::where('hotel_id', $hotelId)->where('status', 'pending')->count(),
            'in_progress' => Maintenance::where('hotel_id', $hotelId)->where('status', 'in_progress')->count(),
            'completed' => Maintenance::where('hotel_id', $hotelId)->where('status', 'completed')->count(),
            'high_priority' => Maintenance::where('hotel_id', $hotelId)->where('priority', 'high')->count(),
            'urgent_priority' => Maintenance::where('hotel_id', $hotelId)->where('priority', 'urgent')->count(),
            'rooms_under_maintenance' => Room::where('hotel_id', $hotelId)->where('status', 'maintenance')->count(),
        ];
        
        return view('maintenance.index', compact('maintenances', 'stats', 'rooms', 'technicians'));
    }

    public function create()
    {
        $hotelId = $this->tenantHotelIdOrAbort();
        $rooms = Room::where('hotel_id', $hotelId)->where('status', '!=', 'maintenance')->orderBy('room_number')->get();
        $technicians = Staff::where('hotel_id', $hotelId)->where('status', 'active')
            ->orderBy('first_name')
            ->orderBy('last_name')
            ->get(['id', 'first_name', 'last_name', 'email', 'employee_id']);
        return view('maintenance.create', compact('rooms', 'technicians'));
    }

    public function store(Request $request)
    {
        $hotelId = $this->tenantHotelIdOrAbort();

        $request->validate([
            'title' => 'required|string|max:255',
            'description' => 'nullable|string',
            'location_type' => 'required|string',
            'room_id' => [
                'nullable',
                Rule::exists('rooms', 'id')->where(function ($query) use ($hotelId) {
                    $query->where('hotel_id', $hotelId);
                }),
            ],
            'common_area' => 'nullable|string',
            'facility' => 'nullable|string',
            'exterior_area' => 'nullable|string',
            'equipment' => 'nullable|string',
            'other_location' => 'nullable|string',
            'location_details' => 'nullable|string',
            'assigned_to' => [
                'nullable',
                Rule::exists('staff', 'id')->where(function ($query) use ($hotelId) {
                    $query->where('hotel_id', $hotelId);
                }),
            ],
            'priority' => 'required|in:low,medium,high,urgent',
            'maintenance_type' => 'required|in:repair,preventive,inspection,cleaning,installation,replacement',
            'scheduled_date' => 'nullable|date|after_or_equal:today',
            'estimated_cost' => 'nullable|numeric|min:0',
            'estimated_duration' => 'nullable|integer|min:1',
        ]);

        DB::transaction(function () use ($request) {
            // Determine the specific location string
            $location = '';
            if ($request->location_type === 'room') {
                $room = Room::where('hotel_id', $hotelId)->find($request->room_id);
                $location = $room ? "Room " . $room->room_number : "Guest Room";
            } else {
                $specificLocation = $request->input($request->location_type);
                if (!$specificLocation && $request->location_type === 'other') {
                    $specificLocation = $request->other_location;
                }
                
                $location = ucwords(str_replace('_', ' ', $request->location_type)) . ": " . ucwords(str_replace('_', ' ', $specificLocation));
            }
            
            if ($request->location_details) {
                $location .= " (" . $request->location_details . ")";
            }

            $maintenanceData = [
                'hotel_id' => $hotelId,
                'title' => $request->title,
                'description' => $request->description,
                'room_id' => $request->location_type === 'room' ? $request->room_id : null,
                'location' => $location,
                'assigned_to' => $request->assigned_to,
                'reported_by' => auth()->id(),
                'priority' => $request->priority,
                'status' => 'pending',
                'reported_date' => now(),
                'scheduled_date' => $request->scheduled_date,
                'estimated_cost' => $request->estimated_cost,
                'estimated_duration' => $request->estimated_duration,
                'maintenance_type' => $request->maintenance_type,
            ];

            $maintenance = Maintenance::create($maintenanceData);

            // Update room status to maintenance if it's a repair that affects room availability
            if ($request->location_type === 'room' && $request->room_id && in_array($request->maintenance_type, ['repair', 'inspection']) && in_array($request->priority, ['high', 'urgent'])) {
                Room::where('hotel_id', $hotelId)->where('id', $request->room_id)->update(['status' => 'maintenance']);
            }
        });

        return redirect()->route('maintenance.index')->with('success', 'Maintenance request created successfully.');
    }

public function show(Maintenance $maintenance)
{
    abort_unless($maintenance->hotel_id == $this->tenantHotelIdOrAbort(), 404);
    // Eager load the room relationship
    $maintenance->load('room.roomType');
    
    return view('maintenance.show', [
        'maintenance' => $maintenance,
        'room' => $maintenance->room // Pass the room to the view
    ]);
}
    public function edit(Maintenance $maintenance)
    {
        $hotelId = $this->tenantHotelIdOrAbort();
        abort_unless($maintenance->hotel_id == $hotelId, 404);
        $rooms = Room::where('hotel_id', $hotelId)->orderBy('room_number')->get();
        $technicians = Staff::where('hotel_id', $hotelId)->where('status', 'active')
            ->orderBy('first_name')
            ->orderBy('last_name')
            ->get(['id', 'first_name', 'last_name', 'email', 'employee_id']);
        return view('maintenance.edit', compact('maintenance', 'rooms', 'technicians'));
    }

    public function update(Request $request, Maintenance $maintenance)
    {
        $hotelId = $this->tenantHotelIdOrAbort();
        abort_unless($maintenance->hotel_id == $hotelId, 404);

        $request->validate([
            'title' => 'required|string|max:255',
            'description' => 'nullable|string',
            'room_id' => [
                'nullable',
                Rule::exists('rooms', 'id')->where(function ($query) use ($hotelId) {
                    $query->where('hotel_id', $hotelId);
                }),
            ],
            'location' => 'nullable|string|max:255',
            'assigned_to' => [
                'nullable',
                Rule::exists('staff', 'id')->where(function ($query) use ($hotelId) {
                    $query->where('hotel_id', $hotelId);
                }),
            ],
            'priority' => 'required|in:low,medium,high,urgent',
            'status' => 'required|in:pending,in_progress,completed,cancelled',
            'maintenance_type' => 'required|in:repair,preventive,inspection,cleaning,installation,replacement',
            'scheduled_date' => 'nullable|date',
            'completed_date' => 'nullable|date|after_or_equal:reported_date',
            'estimated_cost' => 'nullable|numeric|min:0',
            'actual_cost' => 'nullable|numeric|min:0',
            'estimated_duration' => 'nullable|integer|min:1',
            'actual_duration' => 'nullable|integer|min:0',
            'resolution_notes' => 'nullable|string',
            'materials_used' => 'nullable|string|max:500',
        ]);

        DB::transaction(function () use ($request, $maintenance) {
            $oldRoomId = $maintenance->room_id;
            $oldStatus = $maintenance->status;
            $oldMaintenanceType = $maintenance->maintenance_type;
            
            // Auto-set completed_date if status is changed to completed
            $updateData = $request->all();
            if ($request->status === 'completed' && empty($request->completed_date)) {
                $updateData['completed_date'] = now();
            }
            
            // Auto-set started_date if status is changed to in_progress and not set
            if ($request->status === 'in_progress' && empty($maintenance->started_date)) {
                $updateData['started_date'] = now();
            }
            
            $maintenance->update($updateData);
            
            // Handle room status changes based on maintenance type and status
            $this->updateRoomStatus($maintenance, $oldRoomId, $oldStatus, $oldMaintenanceType);
        });

        return redirect()->route('maintenance.index')->with('success', 'Maintenance request updated successfully.');
    }

    public function destroy(Maintenance $maintenance)
    {
        abort_unless($maintenance->hotel_id == $this->tenantHotelIdOrAbort(), 404);
        DB::transaction(function () use ($maintenance) {
            // Restore room status if maintenance was affecting it
            if ($maintenance->room_id && $maintenance->status !== 'completed' && in_array($maintenance->maintenance_type, ['repair', 'inspection'])) {
                Room::where('hotel_id', $this->tenantHotelIdOrAbort())->where('id', $maintenance->room_id)->update(['status' => 'available']);
            }
            $maintenance->delete();
        });

        return redirect()->route('maintenance.index')->with('success', 'Maintenance request deleted successfully.');
    }

    public function export(Request $request)
    {
        $hotelId = $this->tenantHotelIdOrAbort();
        $query = Maintenance::where('hotel_id', $hotelId)->with(['room', 'assignedTechnician', 'reportedBy']);

        // Apply filters for export
        if ($request->has('status') && $request->status != '') {
            $query->where('status', $request->status);
        }
        
        if ($request->has('date_from') && $request->date_from != '') {
            $query->whereDate('reported_date', '>=', $request->date_from);
        }
        
        if ($request->has('date_to') && $request->date_to != '') {
            $query->whereDate('reported_date', '<=', $request->date_to);
        }
        
        if ($request->has('priority') && $request->priority != '') {
            $query->where('priority', $request->priority);
        }

        $maintenances = $query->orderBy('created_at', 'desc')->get();

        $fileName = 'maintenance_requests_' . date('Y-m-d_His') . '.csv';
        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => "attachment; filename=$fileName",
        ];

        $callback = function() use ($maintenances) {
            $file = fopen('php://output', 'w');
            
            // Headers
            fputcsv($file, [
                'ID', 'Title', 'Description', 'Room', 'Priority', 'Status', 
                'Maintenance Type', 'Reported Date', 'Scheduled Date', 'Started Date',
                'Completed Date', 'Assigned To', 'Reported By', 'Estimated Cost (UGX)', 
                'Actual Cost (UGX)', 'Estimated Duration', 'Actual Duration', 'Resolution Notes'
            ]);
            
            // Data
            foreach ($maintenances as $maintenance) {
                fputcsv($file, [
                    $maintenance->id,
                    $maintenance->title,
                    $maintenance->description,
                    $maintenance->room->room_number,
                    ucfirst($maintenance->priority),
                    ucfirst(str_replace('_', ' ', $maintenance->status)),
                    ucfirst($maintenance->maintenance_type),
                    $maintenance->reported_date->format('Y-m-d H:i'),
                    $maintenance->scheduled_date?->format('Y-m-d H:i') ?? 'N/A',
                    $maintenance->started_date?->format('Y-m-d H:i') ?? 'N/A',
                    $maintenance->completed_date?->format('Y-m-d H:i') ?? 'N/A',
                    $maintenance->assignedTechnician ? 
                        $maintenance->assignedTechnician->first_name . ' ' . $maintenance->assignedTechnician->last_name . ' (' . $maintenance->assignedTechnician->employee_id . ')' : 'Not Assigned',
                    $maintenance->reportedBy->email,
                    $maintenance->estimated_cost ?? '0.00',
                    $maintenance->actual_cost ?? '0.00',
                    $maintenance->estimated_duration ?? 'N/A',
                    $maintenance->actual_duration ?? 'N/A',
                    $maintenance->resolution_notes ?? 'N/A'
                ]);
            }
            
            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }

    /**
     * Show maintenance requests for a specific room
     */
    public function byRoom($roomId)
    {
        $hotelId = $this->tenantHotelIdOrAbort();
        $room = Room::where('hotel_id', $hotelId)->findOrFail($roomId);
        $maintenances = Maintenance::where('hotel_id', $hotelId)
            ->where('room_id', $roomId)
            ->with(['assignedTechnician', 'reportedBy'])
            ->orderBy('created_at', 'desc')
            ->paginate(10);
            
        return view('maintenance.by-room', compact('room', 'maintenances'));
    }

    /**
     * Show maintenance requests assigned to current user (technician/staff)
     */
    public function myAssignments()
    {
        $hotelId = $this->tenantHotelIdOrAbort();
        // This method should still use User model since it's for the currently logged-in user
        $maintenances = Maintenance::where('hotel_id', $hotelId)
            ->where('assigned_to', auth()->id())
            ->with(['room', 'reportedBy'])
            ->orderBy('priority', 'desc')
            ->orderBy('created_at', 'desc')
            ->paginate(15);
            
        return view('maintenance.my-assignments', compact('maintenances'));
    }

    /**
     * Update status of assigned maintenance (for technicians)
     */
    public function updateStatus(Request $request, Maintenance $maintenance)
    {
        abort_unless($maintenance->hotel_id == $this->tenantHotelIdOrAbort(), 404);
        // Check if user is assigned to this maintenance or is admin
        if ($maintenance->assigned_to !== auth()->id() && !$this->isAdmin()) {
            return redirect()->back()->with('error', 'You are not authorized to update this maintenance request.');
        }

        $request->validate([
            'status' => 'required|in:pending,in_progress,completed,cancelled',
            'resolution_notes' => 'required_if:status,completed,cancelled|string|max:1000',
            'actual_cost' => 'nullable|numeric|min:0',
            'actual_duration' => 'nullable|integer|min:1',
            'materials_used' => 'nullable|string|max:500',
        ]);

        DB::transaction(function () use ($request, $maintenance) {
            $oldStatus = $maintenance->status;
            
            $updateData = [
                'status' => $request->status,
                'resolution_notes' => $request->resolution_notes,
                'actual_cost' => $request->actual_cost,
                'actual_duration' => $request->actual_duration,
                'materials_used' => $request->materials_used,
            ];

            // Auto-set dates based on status changes
            if ($request->status === 'completed' && $oldStatus !== 'completed') {
                $updateData['completed_date'] = now();
                if (empty($maintenance->started_date)) {
                    $updateData['started_date'] = now();
                }
            } elseif ($request->status === 'in_progress' && empty($maintenance->started_date)) {
                $updateData['started_date'] = now();
            }

            $maintenance->update($updateData);

            // Update room status if maintenance is completed
            if ($request->status === 'completed' && in_array($maintenance->maintenance_type, ['repair', 'inspection'])) {
                Room::where('hotel_id', $this->tenantHotelIdOrAbort())->where('id', $maintenance->room_id)->update(['status' => 'available']);
            }
        });

        return redirect()->back()->with('success', 'Maintenance status updated successfully.');
    }

    /**
     * Helper method to handle room status updates
     */
    private function updateRoomStatus($maintenance, $oldRoomId, $oldStatus, $oldMaintenanceType)
    {
        $hotelId = $this->tenantHotelIdOrAbort();
        $room = Room::where('hotel_id', $hotelId)->find($maintenance->room_id);
        if (!$room) return;
        
        // If maintenance is completed and was affecting room availability, set room to available
        if ($maintenance->status === 'completed' && in_array($maintenance->maintenance_type, ['repair', 'inspection'])) {
            $room->update(['status' => 'available']);
        }
        // If maintenance is in progress or pending and affects room availability, set room to maintenance
        elseif (in_array($maintenance->status, ['in_progress', 'pending']) && 
                in_array($maintenance->maintenance_type, ['repair', 'inspection']) &&
                in_array($maintenance->priority, ['high', 'urgent'])) {
            $room->update(['status' => 'maintenance']);
        }
        
        // If room was changed, update old room status
        if ($oldRoomId != $maintenance->room_id && $oldStatus !== 'completed') {
            $oldRoom = Room::where('hotel_id', $hotelId)->find($oldRoomId);
            if ($oldRoom && in_array($oldMaintenanceType, ['repair', 'inspection'])) {
                $oldRoom->update(['status' => 'available']);
            }
        }
    }

    /**
     * Check if current user is admin
     */
    private function isAdmin()
    {
        return in_array(auth()->user()->role, ['admin', 'super_admin']);
    }
}