package handlers

import (
	"fmt"
	"strconv"
	"time"

	"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
	"github.com/gofiber/fiber/v2"
)

// GetALLPrematchOdds
// @Summary Retrieve all prematch odds
// @Description Retrieve all prematch odds from the database
// @Tags prematch
// @Accept json
// @Produce json
// @Success 200 {array} domain.Odd
// @Failure 500 {object} response.APIResponse
// @Router /odds [get]
func (h *Handler) GetALLPrematchOdds(c *fiber.Ctx) error {

	odds, err := h.prematchSvc.GetALLPrematchOdds(c.Context())
	if err != nil {
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve all prematch odds", nil, nil)
	}

	return response.WriteJSON(c, fiber.StatusOK, "All prematch odds retrieved successfully", odds, nil)

}

// GetRawOddsByMarketID
// @Summary Retrieve raw odds by Market ID
// @Description Retrieve raw odds records using a Market ID
// @Tags prematch
// @Accept json
// @Produce json
// @Param upcoming_id path string true "Upcoming ID"
// @Param market_id path string true "Market ID"
// @Success 200 {array} domain.RawOddsByMarketID
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /odds/upcoming/{upcoming_id}/market/{market_id} [get]
func (h *Handler) GetRawOddsByMarketID(c *fiber.Ctx) error {

	marketID := c.Params("market_id")
	upcomingID := c.Params("upcoming_id")
	if marketID == "" {
		return response.WriteJSON(c, fiber.StatusBadRequest, "Missing market_id", nil, nil)
	}

	if upcomingID == "" {
		return response.WriteJSON(c, fiber.StatusBadRequest, "Missing upcoming_id", nil, nil)
	}

	rawOdds, err := h.prematchSvc.GetRawOddsByMarketID(c.Context(), marketID, upcomingID)
	if err != nil {
		fmt.Printf("Failed to fetch raw odds: %v market_id:%v upcomingID:%v\n", err, marketID, upcomingID)
		h.logger.Error("failed to fetch raw odds", "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve raw odds", err, nil)
	}

	return response.WriteJSON(c, fiber.StatusOK, "Raw odds retrieved successfully", rawOdds, nil)

}

// @Summary Retrieve all upcoming events
// @Description Retrieve all upcoming events from the database
// @Tags prematch
// @Accept json
// @Produce json
// @Param page query int false "Page number"
// @Param page_size query int false "Page size"
// @Param league_id query string false "League ID Filter"
// @Param sport_id query string false "Sport ID Filter"
// @Param cc query string false "Country Code Filter"
// @Param first_start_time query string false "Start Time"
// @Param last_start_time query string false "End Time"
// @Success 200 {array} domain.UpcomingEvent
// @Failure 500 {object} response.APIResponse
// @Router /events [get]
func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error {
	page := c.QueryInt("page", 1)
	pageSize := c.QueryInt("page_size", 10)
	limit := domain.ValidInt64{
		Value: int64(pageSize),
		Valid: true,
	}
	offset := domain.ValidInt64{
		Value: int64(page - 1),
		Valid: true,
	}

	leagueIDQuery := c.Query("league_id")
	var leagueID domain.ValidInt32
	if leagueIDQuery != "" {
		leagueIDInt, err := strconv.Atoi(leagueIDQuery)
		if err != nil {
			h.logger.Error("invalid league id", "error", err)
			return response.WriteJSON(c, fiber.StatusBadRequest, "invalid league id", nil, nil)
		}
		leagueID = domain.ValidInt32{
			Value: int32(leagueIDInt),
			Valid: true,
		}
	}
	sportIDQuery := c.Query("sport_id")
	var sportID domain.ValidInt32
	if sportIDQuery != "" {
		sportIDint, err := strconv.Atoi(sportIDQuery)
		if err != nil {
			h.logger.Error("invalid sport id", "error", err)
			return response.WriteJSON(c, fiber.StatusBadRequest, "invalid sport id", nil, nil)
		}
		sportID = domain.ValidInt32{
			Value: int32(sportIDint),
			Valid: true,
		}
	}
	firstStartTimeQuery := c.Query("first_start_time")
	var firstStartTime domain.ValidTime
	if firstStartTimeQuery != "" {
		firstStartTimeParsed, err := time.Parse(time.RFC3339, firstStartTimeQuery)
		if err != nil {
			h.logger.Error("invalid start_time format", "error", err)
			return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
		}
		firstStartTime = domain.ValidTime{
			Value: firstStartTimeParsed,
			Valid: true,
		}
	}

	lastStartTimeQuery := c.Query("last_start_time")
	var lastStartTime domain.ValidTime
	if lastStartTimeQuery != "" {
		lastStartTimeParsed, err := time.Parse(time.RFC3339, lastStartTimeQuery)
		if err != nil {
			h.logger.Error("invalid start_time format", "error", err)
			return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
		}
		lastStartTime = domain.ValidTime{
			Value: lastStartTimeParsed,
			Valid: true,
		}
	}

	countryCodeQuery := c.Query("cc")
	countryCode := domain.ValidString{
		Value: countryCodeQuery,
		Valid: countryCodeQuery != "",
	}
	events, total, err := h.eventSvc.GetPaginatedUpcomingEvents(
		c.Context(), domain.EventFilter{
			SportID:        sportID,
			LeagueID:       leagueID,
			FirstStartTime: firstStartTime,
			LastStartTime:  lastStartTime,
			Limit:          limit,
			Offset:         offset,
			CountryCode:    countryCode,
		})

	// fmt.Printf("League ID: %v", leagueID)
	if err != nil {
		h.logger.Error("getting error", "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve all upcoming events", nil, nil)
	}

	return response.WritePaginatedJSON(c, fiber.StatusOK, "All upcoming events retrieved successfully", events, nil, page, int(total))

}

// @Summary Retrieve an upcoming by ID
// @Description Retrieve an upcoming event by ID
// @Tags prematch
// @Accept json
// @Produce json
// @Param id path string true "ID"
// @Success 200 {object} domain.UpcomingEvent
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /events/{id} [get]
func (h *Handler) GetUpcomingEventByID(c *fiber.Ctx) error {

	id := c.Params("id")
	if id == "" {
		return response.WriteJSON(c, fiber.StatusBadRequest, "Missing id", nil, nil)
	}

	event, err := h.eventSvc.GetUpcomingEventByID(c.Context(), id)
	if err != nil {
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve upcoming event", nil, nil)
	}

	return response.WriteJSON(c, fiber.StatusOK, "Upcoming event retrieved successfully", event, nil)

}

// @Summary Retrieve prematch odds by upcoming ID (FI)
// @Description Retrieve prematch odds by upcoming event ID (FI from Bet365) with optional pagination
// @Tags prematch
// @Accept json
// @Produce json
// @Param upcoming_id path string true "Upcoming Event ID (FI)"
// @Param limit query int false "Number of results to return (default: 10)"
// @Param offset query int false "Number of results to skip (default: 0)"
// @Success 200 {array} domain.Odd
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /odds/upcoming/{upcoming_id} [get]
func (h *Handler) GetOddsByUpcomingID(c *fiber.Ctx) error {

	upcomingID := c.Params("upcoming_id")
	if upcomingID == "" {
		return response.WriteJSON(c, fiber.StatusBadRequest, "Missing upcoming_id", nil, nil)
	}

	limit, err := strconv.Atoi(c.Query("limit", "10")) // Default limit is 10
	if err != nil || limit <= 0 {
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid limit value", nil, nil)
	}

	offset, err := strconv.Atoi(c.Query("offset", "0")) // Default offset is 0
	if err != nil || offset < 0 {
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid offset value", nil, nil)
	}

	odds, err := h.prematchSvc.GetPrematchOddsByUpcomingID(c.Context(), upcomingID)
	if err != nil {
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve prematch odds", nil, nil)
	}

	return response.WriteJSON(c, fiber.StatusOK, "Prematch odds retrieved successfully", odds, nil)

}

type UpdateEventStatusReq struct {
}

// SetEventStatusToRemoved godoc
// @Summary Set the event status to removed
// @Description Set the event status to removed
// @Tags event
// @Accept json
// @Produce json
// @Param id path int true "Event ID"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /events/{id} [delete]
func (h *Handler) SetEventStatusToRemoved(c *fiber.Ctx) error {
	eventID := c.Params("id")
	err := h.eventSvc.UpdateEventStatus(c.Context(), eventID, domain.STATUS_REMOVED)

	if err != nil {
		h.logger.Error("Failed to update event status", "eventID", eventID, "error", err)
	}

	return response.WriteJSON(c, fiber.StatusOK, "Event updated successfully", nil, nil)

}
