package tender

import (
	"strconv"
	"strings"
	"tm/pkg/logger"
	"tm/pkg/response"

	"github.com/asaskevich/govalidator"
	"github.com/labstack/echo/v4"
)

// TenderHandler handles tender-related HTTP requests
type TenderHandler struct {
	service TenderService
	logger  logger.Logger
}

// NewTenderHandler creates a new tender handler
func NewTenderHandler(service TenderService, logger logger.Logger) *TenderHandler {
	return &TenderHandler{
		service: service,
		logger:  logger,
	}
}

// GetTender retrieves a tender by ID
// @Summary Get tender by ID
// @Description Retrieve a specific tender by its ID
// @Tags Admin-Tenders
// @Produce json
// @Param id path string true "Tender ID"
// @Success 200 {object} response.APIResponse{data=TenderResponse}
// @Failure 404 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /admin/tenders/{id} [get]
// @Security BearerAuth
func (h *TenderHandler) GetTender(c echo.Context) error {
	id := c.Param("id")
	if id == "" {
		return response.BadRequest(c, "Tender ID is required", "ID parameter cannot be empty")
	}

	tender, err := h.service.GetTenderByID(c.Request().Context(), id)
	if err != nil {
		return response.NotFound(c, "Tender not found")
	}

	return response.Success(c, tender, "Tender retrieved successfully")
}

// UpdateTender updates an existing tender
// @Summary Update tender
// @Description Update an existing tender with the provided information
// @Tags Admin-Tenders
// @Accept json
// @Produce json
// @Param id path string true "Tender ID"
// @Param tender body UpdateTenderRequest true "Updated tender information"
// @Success 200 {object} response.APIResponse{data=TenderResponse}
// @Failure 400 {object} response.APIResponse
// @Failure 404 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /admin/tenders/{id} [put]
// @Security BearerAuth
func (h *TenderHandler) UpdateTender(c echo.Context) error {
	id := c.Param("id")
	if id == "" {
		return response.BadRequest(c, "Tender ID is required", "ID parameter cannot be empty")
	}

	var req UpdateTenderRequest
	if err := c.Bind(&req); err != nil {
		return response.ValidationError(c, "Invalid request format", err.Error())
	}

	req.ID = id

	if _, err := govalidator.ValidateStruct(req); err != nil {
		return response.ValidationError(c, "Validation failed", err.Error())
	}

	tender, err := h.service.UpdateTender(c.Request().Context(), req)
	if err != nil {
		if err.Error() == "tender not found" {
			return response.NotFound(c, "Tender not found")
		}
		return response.InternalServerError(c, "Failed to update tender")
	}

	return response.Success(c, tender.ToTenderResponse(), "Tender updated successfully")
}

// DeleteTender deletes a tender
// @Summary Delete tender
// @Description Delete a tender by its ID
// @Tags Admin-Tenders
// @Param id path string true "Tender ID"
// @Success 200 {object} response.APIResponse
// @Failure 404 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /admin/tenders/{id} [delete]
// @Security BearerAuth
func (h *TenderHandler) DeleteTender(c echo.Context) error {
	id := c.Param("id")
	if id == "" {
		return response.BadRequest(c, "Tender ID is required", "ID parameter cannot be empty")
	}

	err := h.service.DeleteTender(c.Request().Context(), id)
	if err != nil {
		if err.Error() == "tender not found" {
			return response.NotFound(c, "Tender not found")
		}
		return response.InternalServerError(c, "Failed to delete tender")
	}

	return response.Success(c, map[string]interface{}{"deleted": true}, "Tender deleted successfully")
}

// ListTenders retrieves tenders with pagination and filtering
// @Summary List tenders
// @Description Retrieve tenders with pagination, filtering, and search capabilities with optional company-based matching
// @Tags Admin-Tenders
// @Produce json
// @Param limit query int false "Number of items per page (default: 20, max: 100)"
// @Param offset query int false "Number of items to skip (default: 0)"
// @Param company_id query string false "Company ID for match percentage calculation and sorting"
// @Param query query string false "Search query for title and description"
// @Param notice_type query string false "Filter by notice type code"
// @Param procurement_type query string false "Filter by procurement type code"
// @Param country_codes query []string false "Filter by country codes (comma-separated)"
// @Param status query []string false "Filter by status (comma-separated)"
// @Param source query []string false "Filter by source (comma-separated)"
// @Param min_estimated_value query number false "Minimum estimated value"
// @Param max_estimated_value query number false "Maximum estimated value"
// @Param currency query string false "Filter by currency"
// @Success 200 {object} response.APIResponse{data=map[string]interface{}}
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /admin/tenders [get]
// @Security BearerAuth
func (h *TenderHandler) ListTenders(c echo.Context) error {
	// Parse pagination parameters
	limit := 20
	if l := c.QueryParam("limit"); l != "" {
		if parsed, err := strconv.Atoi(l); err == nil && parsed > 0 && parsed <= 100 {
			limit = parsed
		}
	}

	offset := 0
	if o := c.QueryParam("offset"); o != "" {
		if parsed, err := strconv.Atoi(o); err == nil && parsed >= 0 {
			offset = parsed
		}
	}

	// Build search criteria
	criteria := TenderSearchCriteria{
		Query:           c.QueryParam("query"),
		NoticeType:      c.QueryParam("notice_type"),
		ProcurementType: c.QueryParam("procurement_type"),
		Currency:        c.QueryParam("currency"),
	}

	// Parse array parameters
	if countryCodes := c.QueryParam("country_codes"); countryCodes != "" {
		criteria.CountryCodes = parseStringArray(countryCodes)
	}

	if statuses := c.QueryParam("status"); statuses != "" {
		statusStrings := parseStringArray(statuses)
		criteria.Status = make([]TenderStatus, len(statusStrings))
		for i, s := range statusStrings {
			criteria.Status[i] = TenderStatus(s)
		}
	}

	if sources := c.QueryParam("source"); sources != "" {
		sourceStrings := parseStringArray(sources)
		criteria.Source = make([]TenderSource, len(sourceStrings))
		for i, s := range sourceStrings {
			criteria.Source[i] = TenderSource(s)
		}
	}

	// Parse numeric parameters
	if minValue := c.QueryParam("min_estimated_value"); minValue != "" {
		if parsed, err := strconv.ParseFloat(minValue, 64); err == nil {
			criteria.MinEstimatedValue = &parsed
		}
	}

	if maxValue := c.QueryParam("max_estimated_value"); maxValue != "" {
		if parsed, err := strconv.ParseFloat(maxValue, 64); err == nil {
			criteria.MaxEstimatedValue = &parsed
		}
	}

	// Parse company_id parameter for matching
	var companyID *string
	if companyIDParam := c.QueryParam("company_id"); companyIDParam != "" {
		companyID = &companyIDParam
	}

	req := ListTendersRequest{
		Criteria:  criteria,
		Limit:     limit,
		Offset:    offset,
		CompanyID: companyID,
	}

	result, err := h.service.ListTenders(c.Request().Context(), req)
	if err != nil {
		return response.InternalServerError(c, "Failed to retrieve tenders")
	}

	return response.Success(c, result, "Tenders retrieved successfully")
}

// GetPublicTenders retrieves public tenders for mobile app
// @Summary Get public tenders
// @Description Retrieve active tenders for mobile application users with automatic company-based matching from customer profile
// @Tags Tenders
// @Produce json
// @Param limit query int false "Number of items per page (default: 20, max: 50)"
// @Param offset query int false "Number of items to skip (default: 0)"
// @Param country_code query string false "Filter by country code"
// @Param min_estimated_value query number false "Minimum estimated value"
// @Param max_estimated_value query number false "Maximum estimated value"
// @Param publication_from query number false "Publication from"
// @Param publication_to query number false "Publication to"
// @Success 200 {object} response.APIResponse{data=map[string]interface{}}
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Security BearerAuth
// @Router /api/v1/tenders [get]
func (h *TenderHandler) GetPublicTenders(c echo.Context) error {
	// Parse pagination parameters (more restrictive for public API)
	limit := 20
	if parsed, err := strconv.Atoi(c.QueryParam("limit")); err == nil && parsed > 0 && parsed <= 50 {
		limit = parsed
	}

	offset := 0
	if parsed, err := strconv.Atoi(c.QueryParam("offset")); err == nil && parsed >= 0 {
		offset = parsed
	}

	// Build search criteria for public API (only active tenders)
	criteria := TenderSearchCriteria{
		Status: []TenderStatus{TenderStatusActive},
	}

	if countryCode := c.QueryParam("country_code"); countryCode != "" {
		criteria.CountryCodes = []string{countryCode}
	}

	// Parse numeric parameters
	if parsed, err := strconv.ParseFloat(c.QueryParam("min_estimated_value"), 64); err == nil {
		criteria.MinEstimatedValue = &parsed
	}

	if parsed, err := strconv.ParseFloat(c.QueryParam("max_estimated_value"), 64); err == nil {
		criteria.MaxEstimatedValue = &parsed
	}

	// Get company ID from customer context for automatic matching
	var companyID *string
	if customerCompanyID, ok := c.Get("company_id").(string); ok {
		companyID = &customerCompanyID
	}

	var from *int64
	if fromParam := c.QueryParam("publication_from"); fromParam != "" {
		if parsed, err := strconv.ParseInt(fromParam, 10, 64); err == nil {
			from = &parsed
		}
	}

	var to *int64
	if toParam := c.QueryParam("publication_to"); toParam != "" {
		if parsed, err := strconv.ParseInt(toParam, 10, 64); err == nil {
			to = &parsed
		}
	}

	req := ListTendersRequest{
		Criteria:  criteria,
		Limit:     limit,
		Offset:    offset,
		CompanyID: companyID,
		From:      from,
		To:        to,
	}
	result, err := h.service.ListTenders(c.Request().Context(), req)
	if err != nil {
		return response.InternalServerError(c, "Failed to retrieve tenders")
	}

	return response.Success(c, result, "Tenders retrieved successfully")
}

// GetPublicTenders retrieves public tenders for mobile app
// @Summary Get public tenders
// @Description Retrieve active tenders for mobile application users with automatic company-based matching from customer profile
// @Tags Tenders
// @Produce json
// @Param limit query int false "Number of items per page (default: 20, max: 50)"
// @Param offset query int false "Number of items to skip (default: 0)"
// @Param country_code query string false "Filter by country code"
// @Param min_estimated_value query number false "Minimum estimated value"
// @Param max_estimated_value query number false "Maximum estimated value"
// @Param publication_from query number false "Publication from"
// @Param publication_to query number false "Publication to"
// @Success 200 {object} response.APIResponse{data=map[string]interface{}}
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Security BearerAuth
// @Router /api/v1/tenders/recommend [get]
func (h *TenderHandler) RecommendTenders(c echo.Context) error {
	// Parse pagination parameters (more restrictive for public API)
	limit := 20
	if parsed, err := strconv.Atoi(c.QueryParam("limit")); err == nil && parsed > 0 && parsed <= 50 {
		limit = parsed
	}

	offset := 0
	if parsed, err := strconv.Atoi(c.QueryParam("offset")); err == nil && parsed >= 0 {
		offset = parsed
	}

	// Build search criteria for public API (only active tenders)
	criteria := TenderSearchCriteria{
		Status: []TenderStatus{TenderStatusActive},
	}

	if countryCode := c.QueryParam("country_code"); countryCode != "" {
		criteria.CountryCodes = []string{countryCode}
	}

	// Parse numeric parameters
	if parsed, err := strconv.ParseFloat(c.QueryParam("min_estimated_value"), 64); err == nil {
		criteria.MinEstimatedValue = &parsed
	}

	if parsed, err := strconv.ParseFloat(c.QueryParam("max_estimated_value"), 64); err == nil {
		criteria.MaxEstimatedValue = &parsed
	}

	// Get company ID from customer context for automatic matching
	var companyID *string
	if customerCompanyID, ok := c.Get("company_id").(string); ok {
		companyID = &customerCompanyID
	}

	var from *int64
	if fromParam := c.QueryParam("publication_from"); fromParam != "" {
		if parsed, err := strconv.ParseInt(fromParam, 10, 64); err == nil {
			from = &parsed
		}
	}

	var to *int64
	if toParam := c.QueryParam("publication_to"); toParam != "" {
		if parsed, err := strconv.ParseInt(toParam, 10, 64); err == nil {
			to = &parsed
		}
	}

	result, err := h.service.RecommendTenders(c.Request().Context(), companyID, from, to, limit, offset)
	if err != nil {
		return response.InternalServerError(c, "Failed to retrieve tenders")
	}

	return response.Success(c, result, "Tenders retrieved successfully")
}

// GetPublicTenderDetails retrieves public tender details for mobile app
// @Summary Get public tender details
// @Description Retrieve detailed information about a specific tender for mobile application users
// @Tags Tenders
// @Produce json
// @Param id path string true "Tender ID"
// @Success 200 {object} response.APIResponse{data=map[string]interface{}}
// @Failure 404 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Security BearerAuth
// @Router /api/v1/tenders/details/{id} [get]
func (h *TenderHandler) GetPublicTenderDetails(c echo.Context) error {
	id := c.Param("id")
	if id == "" {
		return response.BadRequest(c, "Tender ID is required", "ID parameter cannot be empty")
	}

	tender, err := h.service.GetTenderByID(c.Request().Context(), id)
	if err != nil {
		return response.NotFound(c, "Tender not found")
	}

	return response.Success(c, tender, "Tender details retrieved successfully")
}

// parseStringArray parses a comma-separated string into a string array
func parseStringArray(s string) []string {
	if s == "" {
		return nil
	}

	result := make([]string, 0)
	for _, item := range strings.Split(s, ",") {
		if trimmed := strings.TrimSpace(item); trimmed != "" {
			result = append(result, trimmed)
		}
	}

	return result
}
