package handlers

import (
	"fmt"

	"time"

	"github.com/gin-gonic/gin"
	"github.com/jackc/pgx/v5/pgxpool"
	"ticketing-backend/internal/utils"
)

type EventHandler struct {
	pool *pgxpool.Pool
}

func NewEventHandler(pool *pgxpool.Pool) *EventHandler {
	return &EventHandler{pool: pool}
}

// ListEvents - GET /api/events (public, published events)
func (h *EventHandler) ListEvents(c *gin.Context) {
	search := c.Query("search")
	location := c.Query("location")
	authPayload, _ := c.Get("authPayload")

	query := `SELECT e.id, e.name, e.description, e.venue, e.event_date, e.sale_start,
		e.sale_end, e.total_capacity, e.remaining_capacity, e.status, e.war_mode,
		e.image_url, e.created_at, u.full_name as organizer_name
		FROM events e
		LEFT JOIN users u ON u.id = e.organizer_id
		WHERE e.status IN ('published', 'active')`

	var args []interface{}
	argIdx := 1

	if authPayload != nil {
		if payload, ok := authPayload.(map[string]interface{}); ok {
			if classID, exists := payload["classId"]; exists && classID != nil {
				args = append(args, classID)
				query += fmt.Sprintf(` AND (
					NOT EXISTS (SELECT 1 FROM event_classes ec WHERE ec.event_id = e.id)
					OR ($%d::uuid IS NOT NULL AND EXISTS (
						SELECT 1 FROM event_classes ec2 WHERE ec2.event_id = e.id AND ec2.class_id = $%d::uuid
					))
				)`, argIdx, argIdx)
				argIdx++
			}
		}
	}

	if search != "" {
		args = append(args, "%"+search+"%")
		query += fmt.Sprintf(` AND (e.name ILIKE $%d OR e.description ILIKE $%d)`, argIdx, argIdx)
		argIdx++
	}

	if location != "" {
		args = append(args, "%"+location+"%")
		query += fmt.Sprintf(` AND e.venue ILIKE $%d`, argIdx)
		argIdx++
	}

	query += ` ORDER BY e.event_date ASC`

	rows, err := h.pool.Query(c.Request.Context(), query, args...)
	if err != nil {
		utils.InternalError(c, "Failed to fetch events")
		return
	}
	defer rows.Close()

	type EventResult struct {
		ID                string   `json:"id"`
		Name              string   `json:"name"`
		Description       *string  `json:"description"`
		Venue             string   `json:"venue"`
		EventDate         string   `json:"event_date"`
		SaleStart         string   `json:"sale_start"`
		SaleEnd           string   `json:"sale_end"`
		TotalCapacity     int      `json:"total_capacity"`
		RemainingCapacity int      `json:"remaining_capacity"`
		Status            string   `json:"status"`
		WarMode           bool     `json:"war_mode"`
		ImageURL          *string  `json:"image_url"`
		CreatedAt         string   `json:"created_at"`
		OrganizerName     *string  `json:"organizer_name"`
	}

	var events []EventResult
	for rows.Next() {
		var e EventResult
		rows.Scan(&e.ID, &e.Name, &e.Description, &e.Venue, &e.EventDate, &e.SaleStart,
			&e.SaleEnd, &e.TotalCapacity, &e.RemainingCapacity, &e.Status, &e.WarMode,
			&e.ImageURL, &e.CreatedAt, &e.OrganizerName)
		events = append(events, e)
	}

	utils.Success(c, gin.H{"events": events})
}

// GetEvent - GET /api/events/:eventId
func (h *EventHandler) GetEvent(c *gin.Context) {
	eventID := c.Param("eventId")

	type EventDetail struct {
		Event         interface{} `json:"event"`
		TicketClasses interface{} `json:"ticketClasses"`
		ServerNow     string      `json:"serverNow"`
	}

	var event struct {
		ID                string  `json:"id"`
		OrganizerID       string  `json:"organizer_id"`
		Name              string  `json:"name"`
		Description       *string `json:"description"`
		Venue             string  `json:"venue"`
		EventDate         string  `json:"event_date"`
		SaleStart         string  `json:"sale_start"`
		SaleEnd           string  `json:"sale_end"`
		TotalCapacity     int     `json:"total_capacity"`
		RemainingCapacity int     `json:"remaining_capacity"`
		Status            string  `json:"status"`
		WarMode           bool    `json:"war_mode"`
		ImageURL          *string `json:"image_url"`
		OrganizerName     *string `json:"organizer_name"`
		CreatedAt         string  `json:"created_at"`
	}

	err := h.pool.QueryRow(c.Request.Context(),
		`SELECT e.id, e.organizer_id, e.name, e.description, e.venue, e.event_date,
			e.sale_start, e.sale_end, e.total_capacity, e.remaining_capacity, e.status,
			e.war_mode, e.image_url, u.full_name as organizer_name, e.created_at
		 FROM events e
		 LEFT JOIN users u ON u.id = e.organizer_id
		 WHERE e.id = $1`, eventID,
	).Scan(&event.ID, &event.OrganizerID, &event.Name, &event.Description, &event.Venue,
		&event.EventDate, &event.SaleStart, &event.SaleEnd, &event.TotalCapacity,
		&event.RemainingCapacity, &event.Status, &event.WarMode, &event.ImageURL,
		&event.OrganizerName, &event.CreatedAt)

	if err != nil {
		utils.NotFound(c, "Event not found")
		return
	}

	// Get ticket classes
	type TC struct {
		ID                string  `json:"id"`
		Name              string  `json:"name"`
		Price             float64 `json:"price"`
		RemainingCapacity int     `json:"remaining_capacity"`
		Description       *string `json:"description"`
		SeatPlanImage     *string `json:"seat_plan_image"`
	}

	rows, err := h.pool.Query(c.Request.Context(),
		`SELECT id, name, price, remaining_capacity, description, seat_plan_image
		 FROM ticket_classes WHERE event_id = $1 ORDER BY price ASC`, eventID,
	)
	if err != nil {
		utils.InternalError(c, "Failed to fetch ticket classes")
		return
	}
	defer rows.Close()

	var ticketClasses []TC
	for rows.Next() {
		var tc TC
		rows.Scan(&tc.ID, &tc.Name, &tc.Price, &tc.RemainingCapacity, &tc.Description, &tc.SeatPlanImage)
		ticketClasses = append(ticketClasses, tc)
	}

	utils.Success(c, EventDetail{
		Event:         event,
		TicketClasses: ticketClasses,
		ServerNow:     fmt.Sprintf("%d", time.Now().UnixMilli()),
	})
}

func (h *EventHandler) GetEventImages(c *gin.Context) {
	eventID := c.Param("eventId")

	rows, err := h.pool.Query(c.Request.Context(),
		`SELECT id, event_id, image_url, display_order FROM event_images
		 WHERE event_id = $1 ORDER BY display_order ASC`, eventID,
	)
	if err != nil {
		utils.Success(c, gin.H{"images": []interface{}{}})
		return
	}
	defer rows.Close()

	type EventImage struct {
		ID       string `json:"id"`
		EventID  string `json:"event_id"`
		ImageURL string `json:"image_url"`
		Order    int    `json:"display_order"`
	}

	var images []EventImage
	for rows.Next() {
		var img EventImage
		rows.Scan(&img.ID, &img.EventID, &img.ImageURL, &img.Order)
		images = append(images, img)
	}

	utils.Success(c, gin.H{"images": images})
}

func (h *EventHandler) ListUserOrders(c *gin.Context) {
	userID, _ := c.Get("userId")

	rows, err := h.pool.Query(c.Request.Context(),
		`SELECT id, event_id, ticket_class_id, quantity, total_amount,
		        buyer_name, buyer_email, status, created_at
		 FROM orders WHERE buyer_id = $1
		 ORDER BY created_at DESC LIMIT 50`, userID,
	)
	if err != nil {
		utils.InternalError(c, "Failed to fetch orders")
		return
	}
	defer rows.Close()

	var orders []gin.H
	for rows.Next() {
		var id, eventID, tcID, bName, bEmail, status string
		var qty int
		var total float64
		var createdAt string
		rows.Scan(&id, &eventID, &tcID, &qty, &total, &bName, &bEmail, &status, &createdAt)
		orders = append(orders, gin.H{
			"id": id, "event_id": eventID, "ticket_class_id": tcID,
			"quantity": qty, "total_amount": total, "buyer_name": bName,
			"buyer_email": bEmail, "status": status, "created_at": createdAt,
		})
	}

	utils.Success(c, gin.H{"orders": orders})
}
