package handlers import ( "database/sql" "fmt" "html/template" "io" "log" "net/http" "os" "strconv" "synlotto-website/helpers" "synlotto-website/models" "time" "github.com/gorilla/csrf" ) func AddTicket(db *sql.DB) http.HandlerFunc { return helpers.AuthMiddleware(func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet { rows, err := db.Query(` SELECT DISTINCT draw_date FROM results_thunderball ORDER BY draw_date DESC `) if err != nil { log.Println("โŒ Failed to load draw dates:", err) http.Error(w, "Unable to load draw dates", http.StatusInternalServerError) return } defer rows.Close() var drawDates []string for rows.Next() { var date string if err := rows.Scan(&date); err == nil { drawDates = append(drawDates, date) } } context := helpers.TemplateContext(w, r) context["csrfField"] = csrf.TemplateField(r) context["DrawDates"] = drawDates tmpl := template.Must(template.New("").Funcs(helpers.TemplateFuncs()).ParseFiles( "templates/layout.html", "templates/account/tickets/add_ticket.html", )) err = tmpl.ExecuteTemplate(w, "layout", context) if err != nil { log.Println("โŒ Template render error:", err) http.Error(w, "Error rendering form", http.StatusInternalServerError) } return } err := r.ParseMultipartForm(10 << 20) if err != nil { http.Error(w, "Invalid form", http.StatusBadRequest) log.Println("โŒ Failed to parse form:", err) return } userID, ok := helpers.GetCurrentUserID(r) if !ok { http.Redirect(w, r, "/login", http.StatusSeeOther) return } game := r.FormValue("game_type") drawDate := r.FormValue("draw_date") purchaseMethod := r.FormValue("purchase_method") purchaseDate := r.FormValue("purchase_date") purchaseTime := r.FormValue("purchase_time") if purchaseTime != "" { purchaseDate += "T" + purchaseTime } imagePath := "" file, handler, err := r.FormFile("ticket_image") if err == nil && handler != nil { defer file.Close() filename := fmt.Sprintf("uploads/ticket_%d_%s", time.Now().UnixNano(), handler.Filename) out, err := os.Create(filename) if err == nil { defer out.Close() io.Copy(out, file) imagePath = filename } } var ballCount, bonusCount int switch game { case "Thunderball": ballCount, bonusCount = 5, 1 case "Lotto": ballCount, bonusCount = 6, 0 case "EuroMillions": ballCount, bonusCount = 5, 2 case "SetForLife": ballCount, bonusCount = 5, 1 default: http.Error(w, "Unsupported game type", http.StatusBadRequest) return } balls := make([][]int, ballCount) bonuses := make([][]int, bonusCount) for i := 1; i <= ballCount; i++ { field := fmt.Sprintf("ball%d[]", i) balls[i-1] = helpers.ParseIntSlice(r.Form[field]) log.Printf("๐Ÿ”ข %s: %v", field, balls[i-1]) } for i := 1; i <= bonusCount; i++ { field := fmt.Sprintf("bonus%d[]", i) bonuses[i-1] = helpers.ParseIntSlice(r.Form[field]) log.Printf("๐ŸŽฏ %s: %v", field, bonuses[i-1]) } lineCount := 0 if len(balls) > 0 { lineCount = len(balls[0]) } log.Println("๐Ÿงพ Total lines to insert:", lineCount) for i := 0; i < lineCount; i++ { b := make([]int, 6) bo := make([]int, 2) valid := true for j := 0; j < ballCount; j++ { if j < len(balls) && i < len(balls[j]) { b[j] = balls[j][i] if b[j] == 0 { valid = false } } } for j := 0; j < bonusCount; j++ { if j < len(bonuses) && i < len(bonuses[j]) { bo[j] = bonuses[j][i] if bo[j] == 0 { valid = false } } } if !valid { log.Printf("โš ๏ธ Skipping invalid line %d (incomplete values)", i+1) continue } _, err := db.Exec(` INSERT INTO my_tickets ( userId, game_type, draw_date, ball1, ball2, ball3, ball4, ball5, ball6, bonus1, bonus2, purchase_method, purchase_date, image_path ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `, userID, game, drawDate, b[0], b[1], b[2], b[3], b[4], b[5], bo[0], bo[1], purchaseMethod, purchaseDate, imagePath, ) if err != nil { log.Println("โŒ Failed to insert ticket line:", err) } else { log.Printf("โœ… Ticket line %d saved", i+1) } } http.Redirect(w, r, "/tickets", http.StatusSeeOther) }) } func SubmitTicket(db *sql.DB) http.HandlerFunc { return helpers.AuthMiddleware(func(w http.ResponseWriter, r *http.Request) { err := r.ParseMultipartForm(10 << 20) if err != nil { http.Error(w, "Invalid form", http.StatusBadRequest) return } userID, ok := helpers.GetCurrentUserID(r) if !ok { http.Redirect(w, r, "/login", http.StatusSeeOther) return } game := r.FormValue("game_type") drawDate := r.FormValue("draw_date") purchaseMethod := r.FormValue("purchase_method") purchaseDate := r.FormValue("purchase_date") purchaseTime := r.FormValue("purchase_time") if purchaseTime != "" { purchaseDate += "T" + purchaseTime } imagePath := "" file, handler, err := r.FormFile("ticket_image") if err == nil && handler != nil { defer file.Close() filename := fmt.Sprintf("uploads/ticket_%d_%s", time.Now().UnixNano(), handler.Filename) out, err := os.Create(filename) if err == nil { defer out.Close() io.Copy(out, file) imagePath = filename } } ballCount := 6 bonusCount := 2 balls := make([][]int, ballCount) bonuses := make([][]int, bonusCount) for i := 1; i <= ballCount; i++ { balls[i-1] = helpers.ParseIntSlice(r.Form["ball"+strconv.Itoa(i)]) } for i := 1; i <= bonusCount; i++ { bonuses[i-1] = helpers.ParseIntSlice(r.Form["bonus"+strconv.Itoa(i)]) } lineCount := len(balls[0]) for i := 0; i < lineCount; i++ { var b [6]int var bo [2]int for j := 0; j < ballCount; j++ { if j < len(balls) && i < len(balls[j]) { b[j] = balls[j][i] } } for j := 0; j < bonusCount; j++ { if j < len(bonuses) && i < len(bonuses[j]) { bo[j] = bonuses[j][i] } } _, err := db.Exec(` INSERT INTO my_tickets ( user_id, game_type, draw_date, ball1, ball2, ball3, ball4, ball5, ball6, bonus1, bonus2, purchase_method, purchase_date, image_path ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `, userID, game, drawDate, b[0], b[1], b[2], b[3], b[4], b[5], bo[0], bo[1], purchaseMethod, purchaseDate, imagePath, ) if err != nil { log.Println("โŒ Insert failed:", err) } } http.Redirect(w, r, "/tickets", http.StatusSeeOther) }) } func GetMyTickets(db *sql.DB) http.HandlerFunc { return helpers.AuthMiddleware(func(w http.ResponseWriter, r *http.Request) { userID, ok := helpers.GetCurrentUserID(r) if !ok { http.Redirect(w, r, "/login", http.StatusSeeOther) return } rows, err := db.Query(` SELECT id, game_type, draw_date, ball1, ball2, ball3, ball4, ball5, ball6, bonus1, bonus2, purchase_method, purchase_date, image_path FROM my_tickets WHERE user_id = ? ORDER BY draw_date DESC, created_at DESC `, userID) if err != nil { log.Println("โŒ Failed to load user tickets:", err) http.Error(w, "Error loading tickets", http.StatusInternalServerError) return } defer rows.Close() var tickets []models.MyTicket for rows.Next() { var t models.MyTicket err := rows.Scan( &t.Id, &t.GameType, &t.DrawDate, &t.Ball1, &t.Ball2, &t.Ball3, &t.Ball4, &t.Ball5, &t.Ball6, &t.Bonus1, &t.Bonus2, &t.PurchaseMethod, &t.PurchaseDate, &t.ImagePath, ) if err == nil { tickets = append(tickets, t) } } context := helpers.TemplateContext(w, r) context["Tickets"] = tickets tmpl := template.Must(template.New("").Funcs(helpers.TemplateFuncs()).ParseFiles( "templates/layout.html", "templates/account/tickets/my_tickets.html", )) tmpl.ExecuteTemplate(w, "layout", context) }) }