package handlers import ( "fmt" "log" "net/http" "strconv" "strings" "tankstopp/internal/models" "tankstopp/internal/views/pages" "github.com/gorilla/mux" ) // VehiclesHandler handles vehicle management page func (h *Handler) VehiclesHandler(w http.ResponseWriter, r *http.Request) { userID, username := h.getCurrentUser(r) if userID == 0 { http.Redirect(w, r, "/login", http.StatusSeeOther) return } // Get user object user, err := h.db.GetUserByID(userID) if err != nil { log.Printf("Error getting user: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) return } // Get vehicles for the user vehicles, err := h.db.GetVehicles(userID) if err != nil { log.Printf("Error getting vehicles: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) return } // Render vehicles page using templ component := pages.VehiclesPage(user, username, vehicles) w.Header().Set("Content-Type", "text/html") err = component.Render(r.Context(), w) if err != nil { log.Printf("Error rendering template: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) } } // AddVehicleHandler handles adding new vehicles func (h *Handler) AddVehicleHandler(w http.ResponseWriter, r *http.Request) { userID, _ := h.getCurrentUser(r) if userID == 0 { http.Redirect(w, r, "/login", http.StatusSeeOther) return } switch r.Method { case "GET": // Get user object user, err := h.db.GetUserByID(userID) if err != nil { log.Printf("Error getting user: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) return } // Render add vehicle form using templ component := pages.AddVehiclePage(user, user.Username) w.Header().Set("Content-Type", "text/html") err = component.Render(r.Context(), w) if err != nil { log.Printf("Error rendering template: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) } case "POST": h.handleAddVehicle(w, r, userID) default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } } // handleAddVehicle processes the form submission for adding vehicles func (h *Handler) handleAddVehicle(w http.ResponseWriter, r *http.Request, userID uint) { err := r.ParseForm() if err != nil { log.Printf("Error parsing form: %v", err) http.Error(w, "Bad request", http.StatusBadRequest) return } // Parse form data form := models.VehicleForm{ Name: strings.TrimSpace(r.FormValue("name")), Make: strings.TrimSpace(r.FormValue("make")), Model: strings.TrimSpace(r.FormValue("model")), LicensePlate: strings.TrimSpace(r.FormValue("license_plate")), FuelType: r.FormValue("fuel_type"), Notes: r.FormValue("notes"), IsActive: r.FormValue("is_active") == "on", } // Parse year if yearStr := r.FormValue("year"); yearStr != "" { if year, err := strconv.Atoi(yearStr); err == nil { form.Year = year } } // Validate form if err := h.validateVehicleForm(&form); err != nil { log.Printf("Validation error: %v", err) http.Redirect(w, r, "/vehicles/add?error="+err.Error(), http.StatusSeeOther) return } // Convert form to vehicle vehicle := form.ToVehicle(userID) // Save to database err = h.db.CreateVehicle(vehicle) if err != nil { log.Printf("Error creating vehicle: %v", err) http.Redirect(w, r, "/vehicles/add?error=Failed+to+create+vehicle", http.StatusSeeOther) return } // Redirect to vehicles page with success message http.Redirect(w, r, "/vehicles?success=Vehicle+added+successfully", http.StatusSeeOther) } // EditVehicleHandler handles editing existing vehicles func (h *Handler) EditVehicleHandler(w http.ResponseWriter, r *http.Request) { userID, _ := h.getCurrentUser(r) if userID == 0 { http.Redirect(w, r, "/login", http.StatusSeeOther) return } vars := mux.Vars(r) idInt, err := strconv.Atoi(vars["id"]) if err != nil { http.Error(w, "Invalid ID", http.StatusBadRequest) return } id := uint(idInt) switch r.Method { case "GET": // Get vehicle vehicle, err := h.db.GetVehicleByID(id, userID) if err != nil { log.Printf("Error getting vehicle: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) return } if vehicle == nil { http.Error(w, "Vehicle not found", http.StatusNotFound) return } // Get user object user, err := h.db.GetUserByID(userID) if err != nil { log.Printf("Error getting user: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) return } // Render edit vehicle form using templ component := pages.EditVehiclePage(user, user.Username, vehicle) w.Header().Set("Content-Type", "text/html") err = component.Render(r.Context(), w) if err != nil { log.Printf("Error rendering template: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) } case "POST": h.handleEditVehicle(w, r, id, userID) default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } } // handleEditVehicle processes the form submission for editing vehicles func (h *Handler) handleEditVehicle(w http.ResponseWriter, r *http.Request, id, userID uint) { err := r.ParseForm() if err != nil { log.Printf("Error parsing form: %v", err) http.Error(w, "Bad request", http.StatusBadRequest) return } // Get existing vehicle existingVehicle, err := h.db.GetVehicleByID(id, userID) if err != nil { log.Printf("Error getting vehicle: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) return } if existingVehicle == nil { http.Error(w, "Vehicle not found", http.StatusNotFound) return } // Parse form data form := models.VehicleForm{ Name: strings.TrimSpace(r.FormValue("name")), Make: strings.TrimSpace(r.FormValue("make")), Model: strings.TrimSpace(r.FormValue("model")), LicensePlate: strings.TrimSpace(r.FormValue("license_plate")), FuelType: r.FormValue("fuel_type"), Notes: r.FormValue("notes"), IsActive: r.FormValue("is_active") == "on", } // Parse year if yearStr := r.FormValue("year"); yearStr != "" { if year, err := strconv.Atoi(yearStr); err == nil { form.Year = year } } // Validate form if err := h.validateVehicleForm(&form); err != nil { log.Printf("Validation error: %v", err) http.Redirect(w, r, fmt.Sprintf("/vehicles/edit/%d?error=%s", id, err.Error()), http.StatusSeeOther) return } // Convert form to vehicle updatedVehicle := form.ToVehicle(userID) updatedVehicle.ID = id updatedVehicle.CreatedAt = existingVehicle.CreatedAt // Update in database err = h.db.UpdateVehicle(updatedVehicle) if err != nil { log.Printf("Error updating vehicle: %v", err) http.Redirect(w, r, fmt.Sprintf("/vehicles/edit/%d?error=Failed+to+update+vehicle", id), http.StatusSeeOther) return } // Redirect to vehicles page with success message http.Redirect(w, r, "/vehicles?success=Vehicle+updated+successfully", http.StatusSeeOther) } // DeleteVehicleHandler handles deleting vehicles func (h *Handler) DeleteVehicleHandler(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } userID, _ := h.getCurrentUser(r) if userID == 0 { http.Redirect(w, r, "/login", http.StatusSeeOther) return } vars := mux.Vars(r) idInt, err := strconv.Atoi(vars["id"]) if err != nil { http.Error(w, "Invalid ID", http.StatusBadRequest) return } id := uint(idInt) // Verify vehicle exists and belongs to user vehicle, err := h.db.GetVehicleByID(id, userID) if err != nil { log.Printf("Error getting vehicle: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) return } if vehicle == nil { http.Error(w, "Vehicle not found", http.StatusNotFound) return } // Note: In a full implementation, we would check for associated fuel stops // For now, we'll allow deletion and rely on database constraints // Delete vehicle err = h.db.DeleteVehicle(id, userID) if err != nil { log.Printf("Error deleting vehicle: %v", err) http.Redirect(w, r, "/vehicles?error=Failed+to+delete+vehicle", http.StatusSeeOther) return } // Redirect to vehicles page with success message http.Redirect(w, r, "/vehicles?success=Vehicle+deleted+successfully", http.StatusSeeOther) } // validateVehicleForm validates the vehicle form data func (h *Handler) validateVehicleForm(form *models.VehicleForm) error { if form.Name == "" { return fmt.Errorf("Vehicle name is required") } if len(form.Name) < 2 { return fmt.Errorf("Vehicle name must be at least 2 characters long") } if form.Make == "" { return fmt.Errorf("Vehicle make is required") } if form.Model == "" { return fmt.Errorf("Vehicle model is required") } if form.FuelType == "" { return fmt.Errorf("Fuel type is required") } // Validate year if provided if form.Year != 0 { currentYear := 2024 // You might want to use time.Now().Year() if form.Year < 1900 || form.Year > currentYear+1 { return fmt.Errorf("Year must be between 1900 and %d", currentYear+1) } } // Validate license plate format if provided if form.LicensePlate != "" { if len(form.LicensePlate) > 20 { return fmt.Errorf("License plate cannot be longer than 20 characters") } } // Validate notes length if provided if len(form.Notes) > 500 { return fmt.Errorf("Notes cannot be longer than 500 characters") } return nil }