package tender_approval

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

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

// Handler handles HTTP requests for tender approval operations
type Handler struct {
	service Service
	logger  logger.Logger
}

// NewHandler creates a new tender approval handler
func NewHandler(service Service, logger logger.Logger) *Handler {
	return &Handler{
		service: service,
		logger:  logger,
	}
}

// CreateTenderApproval creates a new tender approval
// @Summary Create a new tender approval
// @Description Create a new tender approval for a company to approve or reject a tender
// @Tags TenderApprovals
// @Accept json
// @Produce json
// @Param tender_approval body CreateTenderApprovalForm true "Tender approval information"
// @Success 201 {object} response.APIResponse{data=TenderApprovalResponse} "Tender approval created successfully"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid input data"
// @Failure 409 {object} response.APIResponse "Conflict - Tender approval already exists for this tender and company"
// @Failure 422 {object} response.APIResponse "Validation error - Invalid request data"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Security BearerAuth
// @Router /api/v1/tender-approvals [post]
func (h *Handler) ToggleTenderApproval(c echo.Context) error {
	form, err := response.Parse[ToggleTenderApprovalForm](c)
	if err != nil {
		return response.ValidationError(c, "Invalid request data", err.Error())
	}

	// Get company ID from context
	companyID := c.Get("company_id").(string)
	if companyID == "" {
		return response.Unauthorized(c, "Unauthorized")
	}

	tenderApproval, err := h.service.ToggleTenderApproval(c.Request().Context(), form, companyID)
	if err != nil {
		if err.Error() == "tender approval already exists for this tender and company" {
			return response.Conflict(c, err.Error())
		}
		return response.InternalServerError(c, "Failed to create tender approval")
	}

	return response.Success(c, tenderApproval, "Tender approval updated successfully")
}

// GetTenderApproval retrieves a tender approval by ID
// @Summary Get tender approval by ID
// @Description Retrieve detailed tender approval information by ID
// @Tags TenderApprovals
// @Accept json
// @Produce json
// @Param id path string true "Tender Approval ID"
// @Success 200 {object} response.APIResponse{data=TenderApprovalResponse} "Tender approval retrieved successfully"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid tender approval ID"
// @Failure 404 {object} response.APIResponse "Not found - Tender approval not found"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Security BearerAuth
// @Router /api/v1/tender-approvals/{id} [get]
func (h *Handler) GetPublicTenderApproval(c echo.Context) error {
	id := c.Param("id")

	// Get the approval with tender details
	tenderApprovalWithTender, err := h.service.GetTenderApprovalByIDWithTender(c.Request().Context(), id)
	if err != nil {
		if err.Error() == "tender approval not found" {
			return response.NotFound(c, "Tender approval not found")
		}
		return response.InternalServerError(c, "Failed to get tender approval")
	}

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

// GetTenderApprovalByTenderAndCompany retrieves a tender approval by tender ID and company ID
// @Summary Get tender approval by tender and company
// @Description Retrieve tender approval information for a specific tender and company combination
// @Tags TenderApprovals
// @Accept json
// @Produce json
// @Param tender_id path string true "Tender ID"
// @Success 200 {object} response.APIResponse{data=TenderApprovalResponse} "Tender approval retrieved successfully"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid tender ID or company ID"
// @Failure 404 {object} response.APIResponse "Not found - Tender approval not found"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Security BearerAuth
// @Router /api/v1/tender-approvals/tender/{tender_id} [get]
func (h *Handler) GetTenderApprovalByTenderAndCompany(c echo.Context) error {
	companyID := c.Get("company_id").(string)

	if companyID == "" {
		return response.Unauthorized(c, "Unauthorized")
	}

	tenderID := c.Param("tender_id")
	if tenderID == "" {
		return response.BadRequest(c, "Missing required parameters", "tender_id required")
	}

	tenderApprovalWithTender, err := h.service.GetTenderApprovalByTenderAndCompanyWithTender(c.Request().Context(), tenderID, companyID)
	if err != nil {
		if err.Error() == "tender approval not found" {
			return response.NotFound(c, "Tender approval not found")
		}
		return response.InternalServerError(c, "Failed to get tender approval")
	}

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

// GetTenderApprovalsByCompanyID retrieves all tender approvals for a specific company
// @Summary Get tender approvals by company ID
// @Description Retrieve all tender approvals for a specific company with optional filtering
// @Tags TenderApprovals
// @Accept json
// @Produce json
// @Param limit query integer false "Number of approvals per page (1-100)" minimum(1) maximum(100) default(20)
// @Param offset query integer false "Number of approvals to skip for pagination" minimum(0) default(0)
// @Param submission_mode query string false "Filter by submission mode Enums(self-apply, partnership)"
// @Param status query string false "Filter by status Enums(submitted, rejected)"
// @Param created_from query integer false "Filter by created date from (Unix timestamp)"
// @Param created_to query integer false "Filter by created date to (Unix timestamp)"
// @Success 200 {object} response.APIResponse{data=TenderApprovalWithTenderListResponse} "Tender approvals retrieved successfully"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid company ID"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Security BearerAuth
// @Router /api/v1/tender-approvals [get]
func (h *Handler) PublicGetTenderApprovals(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
		}
	}

	companyID := c.Get("company_id").(string)
	if companyID == "" {
		return response.Unauthorized(c, "Unauthorized")
	}

	// Get query parameters for filtering
	submissionModeStr := c.QueryParam("submission_mode")
	statusStr := c.QueryParam("status")

	// Parse submission mode filter
	var submissionMode *SubmissionMode
	if submissionModeStr != "" {
		mode := SubmissionMode(submissionModeStr)
		if mode != SubmissionModeSelfApply && mode != SubmissionModePartnership {
			return response.BadRequest(c, "Invalid submission_mode value", "Must be 'self-apply' or 'partnership'")
		}
		submissionMode = &mode
	}

	// Parse status filter
	var status *ApprovalStatus
	if statusStr != "" {
		statusVal := ApprovalStatus(statusStr)
		if statusVal != ApprovalStatusSubmitted && statusVal != ApprovalStatusRejected {
			return response.BadRequest(c, "Invalid status value", "Must be 'submitted' or 'rejected'")
		}
		status = &statusVal
	}

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

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

	tenderApprovalsWithTender, err := h.service.GetTenderApprovalsByCompanyIDWithTender(c.Request().Context(), companyID, submissionMode, status, from, to, limit, offset)
	if err != nil {
		return response.InternalServerError(c, "Failed to get tender approvals")
	}

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

// **************** Admin Routes ****************

// ListTenderApprovals lists tender approvals with filters and pagination
// @Summary List tender approvals with filters and pagination
// @Description Retrieve a paginated list of tender approvals with filtering options
// @Tags Admin-TenderApprovals
// @Accept json
// @Produce json
// @Param tender_id query string false "Filter by tender ID"
// @Param company_id query string false "Filter by company ID"
// @Param status query array false "Filter by status"
// @Param submission_mode query array false "Filter by submission mode"
// @Param created_at_from query integer false "Filter by creation date from (Unix timestamp)"
// @Param created_at_to query integer false "Filter by creation date to (Unix timestamp)"
// @Param limit query integer false "Number of approvals per page (1-100)" minimum(1) maximum(100) default(20)
// @Param offset query integer false "Number of approvals to skip for pagination" minimum(0) default(0)
// @Param sort_by query string false "Field to sort by" Enums(created_at, updated_at, status, submission_mode) default(created_at)
// @Param sort_order query string false "Sort order" Enums(asc, desc) default(desc)
// @Success 200 {object} response.APIResponse{data=TenderApprovalListResponse} "Tender approvals retrieved successfully"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid query parameters"
// @Failure 422 {object} response.APIResponse "Validation error - Invalid query parameters"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Security BearerAuth
// @Router /admin/v1/tender-approvals [get]
func (h *Handler) ListTenderApprovals(c echo.Context) error {
	form, err := response.Parse[ListTenderApprovalsForm](c)
	if err != nil {
		return response.ValidationError(c, "Invalid request data", err.Error())
	}

	result, err := h.service.ListTenderApprovalsWithTender(c.Request().Context(), form)
	if err != nil {
		return response.InternalServerError(c, "Failed to list tender approvals")
	}

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

// GetTenderApprovalStats returns tender approval statistics
// @Summary Get tender approval statistics
// @Description Get comprehensive tender approval statistics for dashboard
// @Tags Admin-TenderApprovals
// @Accept json
// @Produce json
// @Success 200 {object} response.APIResponse{data=TenderApprovalStatsResponse} "Tender approval statistics retrieved successfully"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Security BearerAuth
// @Router /admin/v1/tender-approvals/stats [get]
func (h *Handler) GetTenderApprovalStats(c echo.Context) error {
	stats, err := h.service.GetTenderApprovalStats(c.Request().Context())
	if err != nil {
		return response.InternalServerError(c, "Failed to get tender approval statistics")
	}

	return response.Success(c, stats, "Tender approval statistics retrieved successfully")
}

// GetCompanyTenderApprovalStats returns company-specific tender approval statistics
// @Summary Get company tender approval statistics
// @Description Get comprehensive tender approval statistics for a specific company
// @Tags TenderApprovals
// @Accept json
// @Produce json
// @Success 200 {object} response.APIResponse{data=CompanyTenderApprovalStatsResponse} "Company tender approval statistics retrieved successfully"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid company ID"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Security BearerAuth
// @Router /api/v1/tender-approvals/stats [get]
func (h *Handler) GetCompanyTenderApprovalStats(c echo.Context) error {
	companyID := c.Get("company_id").(string)
	if companyID == "" {
		return response.Unauthorized(c, "Unauthorized")
	}

	stats, err := h.service.GetCompanyTenderApprovalStats(c.Request().Context(), companyID)
	if err != nil {
		return response.InternalServerError(c, "Failed to get company tender approval statistics")
	}

	return response.Success(c, stats, "Company tender approval statistics retrieved successfully")
}

// GetTenderApprovalsByStatus retrieves tender approvals by status
// @Summary Get tender approvals by status
// @Description Retrieve tender approvals filtered by their status (submitted, rejected)
// @Tags Admin-TenderApprovals
// @Accept json
// @Produce json
// @Param status path string true "Tender approval status" Enums(submitted, rejected)
// @Param limit query integer false "Number of approvals per page (1-100)" minimum(1) maximum(100) default(20)
// @Param offset query integer false "Number of approvals to skip for pagination" minimum(0) default(0)
// @Success 200 {object} response.APIResponse{data=[]TenderApprovalResponse,meta=response.Meta} "Tender approvals retrieved successfully"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid tender approval status"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Security BearerAuth
// @Router /admin/v1/tender-approvals/status/{status} [get]
func (h *Handler) GetTenderApprovalsByStatus(c echo.Context) error {
	statusStr := c.Param("status")
	status := ApprovalStatus(statusStr)

	// Validate status
	if status != ApprovalStatusSubmitted && status != ApprovalStatusRejected {
		return response.BadRequest(c, "Invalid tender approval status", "Must be submitted or rejected")
	}

	limit := 20
	if limitStr := c.QueryParam("limit"); limitStr != "" {
		if parsedLimit, err := strconv.Atoi(limitStr); err == nil && parsedLimit > 0 && parsedLimit <= 100 {
			limit = parsedLimit
		}
	}

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

	tenderApprovalsWithTender, total, err := h.service.GetTenderApprovalsByStatusWithTender(c.Request().Context(), status, limit, offset)
	if err != nil {
		return response.InternalServerError(c, "Failed to retrieve tender approvals by status")
	}

	meta := &response.Meta{
		Total:  int(total),
		Limit:  limit,
		Offset: offset,
	}

	return response.SuccessWithMeta(c, tenderApprovalsWithTender, meta, "Tender approvals retrieved successfully")
}

// GetTenderApprovalsBySubmissionMode retrieves tender approvals by submission mode
// @Summary Get tender approvals by submission mode
// @Description Retrieve tender approvals filtered by their submission mode (self-apply, partnership)
// @Tags Admin-TenderApprovals
// @Accept json
// @Produce json
// @Param submission_mode path string true "Tender approval submission mode" Enums(self-apply, partnership)
// @Param limit query integer false "Number of approvals per page (1-100)" minimum(1) maximum(100) default(20)
// @Param offset query integer false "Number of approvals to skip for pagination" minimum(0) default(0)
// @Success 200 {object} response.APIResponse{data=[]TenderApprovalResponse,meta=response.Meta} "Tender approvals retrieved successfully"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid tender approval submission mode"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Security BearerAuth
// @Router /admin/v1/tender-approvals/submission-mode/{submission_mode} [get]
func (h *Handler) GetTenderApprovalsBySubmissionMode(c echo.Context) error {
	submissionModeStr := c.Param("submission_mode")
	submissionMode := SubmissionMode(submissionModeStr)

	// Validate submission mode
	if submissionMode != SubmissionModeSelfApply && submissionMode != SubmissionModePartnership {
		return response.BadRequest(c, "Invalid tender approval submission mode", "Must be self-apply or partnership")
	}

	limit := 20
	if limitStr := c.QueryParam("limit"); limitStr != "" {
		if parsedLimit, err := strconv.Atoi(limitStr); err == nil && parsedLimit > 0 && parsedLimit <= 100 {
			limit = parsedLimit
		}
	}

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

	tenderApprovalsWithTender, total, err := h.service.GetTenderApprovalsBySubmissionModeWithTender(c.Request().Context(), submissionMode, limit, offset)
	if err != nil {
		return response.InternalServerError(c, "Failed to retrieve tender approvals by submission mode")
	}

	meta := &response.Meta{
		Total:  int(total),
		Limit:  limit,
		Offset: offset,
	}

	return response.SuccessWithMeta(c, tenderApprovalsWithTender, meta, "Tender approvals retrieved successfully")
}

// GetTenderApproval retrieves a tender approval by ID
// @Summary Get tender approval by ID
// @Description Retrieve detailed tender approval information by ID
// @Tags Admin-TenderApprovals
// @Accept json
// @Produce json
// @Param id path string true "Tender Approval ID"
// @Success 200 {object} response.APIResponse{data=TenderApprovalResponse} "Tender approval retrieved successfully"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid tender approval ID"
// @Failure 404 {object} response.APIResponse "Not found - Tender approval not found"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Security BearerAuth
// @Router /admin/v1/tender-approvals/{id} [get]
func (h *Handler) GetTenderApproval(c echo.Context) error {
	id := c.Param("id")

	// Get the approval with tender details
	tenderApprovalWithTender, err := h.service.GetTenderApprovalByIDWithTender(c.Request().Context(), id)
	if err != nil {
		if err.Error() == "tender approval not found" {
			return response.NotFound(c, "Tender approval not found")
		}
		return response.InternalServerError(c, "Failed to get tender approval")
	}

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