package tender_approval

import (
	"context"
	"errors"
	"math"
	"time"
	"tm/internal/tender"
	"tm/pkg/logger"
	"tm/pkg/response"
)

// Service defines business logic for tender approval operations
type Service interface {
	// Core tender approval operations
	CreateTenderApproval(ctx context.Context, form *CreateTenderApprovalForm, companyID string) (*TenderApproval, error)
	GetTenderApprovalByID(ctx context.Context, id string) (*TenderApproval, error)
	GetTenderApprovalByIDWithTender(ctx context.Context, id string) (*TenderApprovalWithTenderResponse, error)
	GetTenderApprovalByTenderAndCompany(ctx context.Context, tenderID, companyID string) (*TenderApproval, error)
	GetTenderApprovalByTenderAndCompanyWithTender(ctx context.Context, tenderID, companyID string) (*TenderApprovalWithTenderResponse, error)
	GetTenderApprovalsByTenderID(ctx context.Context, tenderID string) ([]*TenderApproval, error)
	GetTenderApprovalsByCompanyID(ctx context.Context, companyID string, submissionMode *SubmissionMode, status *ApprovalStatus, from *int64, to *int64, limit int, offset int) ([]*TenderApproval, int64, error)
	GetTenderApprovalsByCompanyIDWithTender(ctx context.Context, companyID string, submissionMode *SubmissionMode, status *ApprovalStatus, from *int64, to *int64, limit int, offset int) (*TenderApprovalWithTenderListResponse, error)
	GetTenderApprovalsByIDs(ctx context.Context, ids []string) ([]*TenderApproval, error)
	UpdateTenderApproval(ctx context.Context, id string, form *UpdateTenderApprovalForm) (*TenderApproval, error)
	UpdateTenderApprovalWithTender(ctx context.Context, id string, form *UpdateTenderApprovalForm) (*TenderApprovalWithTenderResponse, error)
	DeleteTenderApproval(ctx context.Context, id string) error

	// Tender approval listing and search
	ListTenderApprovals(ctx context.Context, form *ListTenderApprovalsForm) (*TenderApprovalListResponse, error)
	ListTenderApprovalsWithTender(ctx context.Context, form *ListTenderApprovalsForm) (*TenderApprovalListResponseWithTender, error)
	SearchTenderApprovals(ctx context.Context, form *TenderApprovalSearchForm) (*TenderApprovalListResponse, error)
	SearchTenderApprovalsByCriteria(ctx context.Context, criteria *TenderApprovalSearchCriteria) ([]*TenderApproval, error)

	// Business operations
	ToggleTenderApproval(ctx context.Context, req *ToggleTenderApprovalForm, companyID string) (*TenderApprovalWithTenderResponse, error)

	// Statistics and analytics
	GetTenderApprovalStats(ctx context.Context) (*TenderApprovalStatsResponse, error)
	GetCompanyTenderApprovalStats(ctx context.Context, companyID string) (*CompanyTenderApprovalStatsResponse, error)
	GetMultipleCompanyTenderApprovalStats(ctx context.Context, companyIDs []string) ([]*CompanyTenderApprovalStatsResponse, error)
	GetAggregatedCompanyStats(ctx context.Context) (*AggregatedCompanyStatsResponse, error)

	// Search and filtering helpers
	GetTenderApprovalsByStatus(ctx context.Context, status ApprovalStatus, limit, offset int) ([]*TenderApproval, int64, error)
	GetTenderApprovalsByStatusWithTender(ctx context.Context, status ApprovalStatus, limit, offset int) ([]*TenderApprovalWithTenderResponse, int64, error)
	GetTenderApprovalsBySubmissionMode(ctx context.Context, submissionMode SubmissionMode, limit, offset int) ([]*TenderApproval, int64, error)
	GetTenderApprovalsBySubmissionModeWithTender(ctx context.Context, submissionMode SubmissionMode, limit, offset int) ([]*TenderApprovalWithTenderResponse, int64, error)
}

// tenderApprovalService implements the Service interface
type tenderApprovalService struct {
	repository    Repository
	tenderService tender.TenderService
	logger        logger.Logger
}

// NewTenderApprovalService creates a new tender approval service
func NewTenderApprovalService(repository Repository, tenderService tender.TenderService, logger logger.Logger) Service {
	return &tenderApprovalService{
		repository:    repository,
		tenderService: tenderService,
		logger:        logger,
	}
}

// CreateTenderApproval creates a new tender approval
func (s *tenderApprovalService) CreateTenderApproval(ctx context.Context, form *CreateTenderApprovalForm, companyID string) (*TenderApproval, error) {
	// Check if tender approval already exists for this tender and company
	existingApproval, _ := s.repository.GetByTenderAndCompany(ctx, form.TenderID, companyID)
	if existingApproval != nil {
		return nil, errors.New("tender approval already exists for this tender and company")
	}

	// Create tender approval
	tenderApproval := &TenderApproval{
		TenderID:       form.TenderID,
		CompanyID:      companyID,
		SubmissionMode: SubmissionMode(form.SubmissionMode),
		Status:         ApprovalStatus(form.Status),
	}

	// Save to database
	err := s.repository.Create(ctx, tenderApproval)
	if err != nil {
		s.logger.Error("Failed to create tender approval", map[string]interface{}{
			"error":      err.Error(),
			"tender_id":  form.TenderID,
			"company_id": companyID,
		})
		return nil, err
	}

	s.logger.Info("Tender approval created successfully", map[string]interface{}{
		"tender_approval_id": tenderApproval.ID,
		"tender_id":          tenderApproval.TenderID,
		"company_id":         tenderApproval.CompanyID,
		"submission_mode":    tenderApproval.SubmissionMode,
		"status":             tenderApproval.Status,
	})

	return tenderApproval, nil
}

// GetTenderApprovalByID retrieves a tender approval by ID
func (s *tenderApprovalService) GetTenderApprovalByID(ctx context.Context, id string) (*TenderApproval, error) {
	tenderApproval, err := s.repository.GetByID(ctx, id)
	if err != nil {
		s.logger.Error("Failed to get tender approval by ID", map[string]interface{}{
			"error":              err.Error(),
			"tender_approval_id": id,
		})
		return nil, err
	}

	s.logger.Info("Tender approval retrieved successfully", map[string]interface{}{
		"tender_approval_id": tenderApproval.ID,
		"tender_id":          tenderApproval.TenderID,
		"company_id":         tenderApproval.CompanyID,
	})

	return tenderApproval, nil
}

// GetTenderApprovalByIDWithTender retrieves a tender approval by ID with tender details
func (s *tenderApprovalService) GetTenderApprovalByIDWithTender(ctx context.Context, id string) (*TenderApprovalWithTenderResponse, error) {
	tenderApproval, err := s.repository.GetByID(ctx, id)
	if err != nil {
		s.logger.Error("Failed to get tender approval by ID", map[string]interface{}{
			"error":              err.Error(),
			"tender_approval_id": id,
		})
		return nil, err
	}

	// Get tender details
	tenderResponse, err := s.tenderService.GetTenderByID(ctx, tenderApproval.TenderID)
	if err != nil {
		s.logger.Warn("Failed to get tender details", map[string]interface{}{
			"tender_id": tenderApproval.TenderID,
			"error":     err.Error(),
		})
		// Return approval without tender details rather than failing completely
		return tenderApproval.ToResponseWithTender(nil), nil
	}

	// Convert tender response to tender details
	tenderDetails := &TenderDetails{
		ID:                  tenderResponse.ID,
		NoticePublicationID: tenderResponse.NoticePublicationID,
		PublicationDate:     tenderResponse.PublicationDate,
		Title:               tenderResponse.Title,
		Description:         tenderResponse.Description,
		ProcurementTypeCode: tenderResponse.ProcurementTypeCode,
		ProcedureCode:       tenderResponse.ProcedureCode,
		EstimatedValue:      tenderResponse.EstimatedValue,
		Currency:            tenderResponse.Currency,
		Duration:            tenderResponse.Duration,
		DurationUnit:        tenderResponse.DurationUnit,
		TenderDeadline:      tenderResponse.TenderDeadline,
		SubmissionDeadline:  tenderResponse.SubmissionDeadline,
		CountryCode:         tenderResponse.CountryCode,
		BuyerOrganization:   &OrganizationResponse{Name: tenderResponse.BuyerOrganization.Name},
		Status:              string(tenderResponse.Status),
	}

	s.logger.Info("Tender approval with tender details retrieved successfully", map[string]interface{}{
		"tender_approval_id": id,
	})

	return tenderApproval.ToResponseWithTender(tenderDetails), nil
}

// GetTenderApprovalByTenderAndCompany retrieves a tender approval by tender ID and company ID
func (s *tenderApprovalService) GetTenderApprovalByTenderAndCompany(ctx context.Context, tenderID, companyID string) (*TenderApproval, error) {
	tenderApproval, err := s.repository.GetByTenderAndCompany(ctx, tenderID, companyID)
	if err != nil {
		s.logger.Error("Failed to get tender approval by tender and company", map[string]interface{}{
			"error":      err.Error(),
			"tender_id":  tenderID,
			"company_id": companyID,
		})
		return nil, err
	}

	s.logger.Info("Tender approval retrieved successfully", map[string]interface{}{
		"tender_approval_id": tenderApproval.ID,
		"tender_id":          tenderApproval.TenderID,
		"company_id":         tenderApproval.CompanyID,
	})

	return tenderApproval, nil
}

// GetTenderApprovalByTenderAndCompanyWithTender retrieves a tender approval by tender ID and company ID with tender details
func (s *tenderApprovalService) GetTenderApprovalByTenderAndCompanyWithTender(ctx context.Context, tenderID, companyID string) (*TenderApprovalWithTenderResponse, error) {
	tenderApproval, err := s.repository.GetByTenderAndCompany(ctx, tenderID, companyID)
	if err != nil {
		s.logger.Error("Failed to get tender approval by tender and company", map[string]interface{}{
			"error":      err.Error(),
			"tender_id":  tenderID,
			"company_id": companyID,
		})
		return nil, err
	}

	// Get tender details
	tenderResponse, err := s.tenderService.GetTenderByID(ctx, tenderApproval.TenderID)
	if err != nil {
		s.logger.Warn("Failed to get tender details", map[string]interface{}{
			"tender_id": tenderApproval.TenderID,
		})
		// Return approval without tender details rather than failing completely
		return tenderApproval.ToResponseWithTender(nil), nil
	}

	// Convert tender response to tender details
	tenderDetails := &TenderDetails{
		ID:                  tenderResponse.ID,
		NoticePublicationID: tenderResponse.NoticePublicationID,
		PublicationDate:     tenderResponse.PublicationDate,
		Title:               tenderResponse.Title,
		Description:         tenderResponse.Description,
		ProcurementTypeCode: tenderResponse.ProcurementTypeCode,
		ProcedureCode:       tenderResponse.ProcedureCode,
		EstimatedValue:      tenderResponse.EstimatedValue,
		Currency:            tenderResponse.Currency,
		Duration:            tenderResponse.Duration,
		DurationUnit:        tenderResponse.DurationUnit,
		TenderDeadline:      tenderResponse.TenderDeadline,
		SubmissionDeadline:  tenderResponse.SubmissionDeadline,
		CountryCode:         tenderResponse.CountryCode,
		BuyerOrganization:   &OrganizationResponse{Name: tenderResponse.BuyerOrganization.Name},
		Status:              string(tenderResponse.Status),
	}

	s.logger.Info("Tender approval with tender details retrieved successfully", map[string]interface{}{
		"tender_approval_id": tenderApproval.ID,
		"tender_id":          tenderApproval.TenderID,
		"company_id":         tenderApproval.CompanyID,
	})

	return tenderApproval.ToResponseWithTender(tenderDetails), nil
}

// GetTenderApprovalsByTenderID retrieves all tender approvals for a specific tender
func (s *tenderApprovalService) GetTenderApprovalsByTenderID(ctx context.Context, tenderID string) ([]*TenderApproval, error) {
	tenderApprovals, err := s.repository.GetByTenderID(ctx, tenderID)
	if err != nil {
		s.logger.Error("Failed to get tender approvals by tender ID", map[string]interface{}{
			"error":     err.Error(),
			"tender_id": tenderID,
		})
		return nil, err
	}

	s.logger.Info("Tender approvals retrieved successfully", map[string]interface{}{
		"tender_id": tenderID,
		"count":     len(tenderApprovals),
	})

	return tenderApprovals, nil
}

// GetTenderApprovalsByCompanyID retrieves all tender approvals for a specific company with optional filters
func (s *tenderApprovalService) GetTenderApprovalsByCompanyID(ctx context.Context, companyID string, submissionMode *SubmissionMode, status *ApprovalStatus, from *int64, to *int64, limit int, offset int) ([]*TenderApproval, int64, error) {
	tenderApprovals, total, err := s.repository.GetByCompanyID(ctx, companyID, submissionMode, status, limit, offset, from, to)
	if err != nil {
		s.logger.Error("Failed to get tender approvals by company ID", map[string]interface{}{
			"error":      err.Error(),
			"company_id": companyID,
		})
		return nil, 0, err
	}

	s.logger.Info("Tender approvals retrieved successfully", map[string]interface{}{
		"company_id": companyID,
		"count":      len(tenderApprovals),
	})

	return tenderApprovals, total, nil
}

// GetTenderApprovalsByCompanyIDWithTender retrieves all tender approvals for a specific company with tender details
func (s *tenderApprovalService) GetTenderApprovalsByCompanyIDWithTender(ctx context.Context, companyID string, submissionMode *SubmissionMode, status *ApprovalStatus, from *int64, to *int64, limit, offset int) (*TenderApprovalWithTenderListResponse, error) {
	tenderApprovals, total, err := s.repository.GetByCompanyID(ctx, companyID, submissionMode, status, limit, offset, from, to)
	if err != nil {
		s.logger.Error("Failed to get tender approvals by company ID", map[string]interface{}{
			"error":      err.Error(),
			"company_id": companyID,
		})
		return nil, err
	}

	// Convert to response with tender details
	responses := &TenderApprovalWithTenderListResponse{
		Approvals: []*TenderApprovalWithTenderResponse{},
		Metadata:  &response.Meta{},
	}
	for _, approval := range tenderApprovals {
		// Get tender details
		tenderResponse, err := s.tenderService.GetTenderByID(ctx, approval.TenderID)
		if err != nil {
			s.logger.Warn("Failed to get tender details", map[string]interface{}{
				"tender_id": approval.TenderID,
				"error":     err.Error(),
			})
			// Continue without tender details rather than failing completely
			responses.Approvals = append(responses.Approvals, approval.ToResponseWithTender(nil))
			continue
		}

		// Convert tender response to tender details
		tenderDetails := &TenderDetails{
			ID:                 tenderResponse.ID,
			Title:              tenderResponse.Title,
			Description:        tenderResponse.Description,
			EstimatedValue:     tenderResponse.EstimatedValue,
			Currency:           tenderResponse.Currency,
			TenderDeadline:     tenderResponse.TenderDeadline,
			SubmissionDeadline: tenderResponse.SubmissionDeadline,
			CountryCode:        tenderResponse.CountryCode,
			BuyerOrganization:  &OrganizationResponse{Name: tenderResponse.BuyerOrganization.Name},
			Status:             string(tenderResponse.Status),
		}

		responses.Approvals = append(responses.Approvals, approval.ToResponseWithTender(tenderDetails))
	}

	responses.Metadata = &response.Meta{
		Total:  int(total),
		Limit:  limit,
		Offset: offset,
		Pages:  int(math.Ceil(float64(total) / float64(limit))),
		Page:   int(math.Ceil(float64(offset) / float64(limit))),
	}

	s.logger.Info("Tender approvals with tender details retrieved successfully", map[string]interface{}{
		"company_id": companyID,
		"count":      len(responses.Approvals),
	})

	return responses, nil
}

// GetTenderApprovalsByIDs retrieves multiple tender approvals by their IDs
func (s *tenderApprovalService) GetTenderApprovalsByIDs(ctx context.Context, ids []string) ([]*TenderApproval, error) {
	if len(ids) == 0 {
		return []*TenderApproval{}, nil
	}

	tenderApprovals, err := s.repository.GetByIDs(ctx, ids)
	if err != nil {
		s.logger.Error("Failed to get tender approvals by IDs", map[string]interface{}{
			"error": err.Error(),
			"ids":   ids,
		})
		return nil, err
	}

	s.logger.Info("Tender approvals retrieved successfully", map[string]interface{}{
		"requested_count": len(ids),
		"found_count":     len(tenderApprovals),
	})

	return tenderApprovals, nil
}

// UpdateTenderApproval updates a tender approval
func (s *tenderApprovalService) UpdateTenderApproval(ctx context.Context, id string, form *UpdateTenderApprovalForm) (*TenderApproval, error) {
	// Get existing tender approval
	tenderApproval, err := s.repository.GetByID(ctx, id)
	if err != nil {
		s.logger.Error("Failed to get tender approval for update", map[string]interface{}{
			"error":              err.Error(),
			"tender_approval_id": id,
		})
		return nil, errors.New("tender approval not found")
	}

	// Update fields if provided
	if form.SubmissionMode != nil {
		tenderApproval.SubmissionMode = SubmissionMode(*form.SubmissionMode)
	}

	if form.Status != nil {
		tenderApproval.Status = ApprovalStatus(*form.Status)
	}

	// Set updated timestamp
	tenderApproval.UpdatedAt = time.Now().Unix()

	// Update in database
	err = s.repository.Update(ctx, tenderApproval)
	if err != nil {
		s.logger.Error("Failed to update tender approval", map[string]interface{}{
			"error":              err.Error(),
			"tender_approval_id": id,
		})
		return nil, errors.New("failed to update tender approval")
	}

	s.logger.Info("Tender approval updated successfully", map[string]interface{}{
		"tender_approval_id": tenderApproval.ID,
		"tender_id":          tenderApproval.TenderID,
		"company_id":         tenderApproval.CompanyID,
	})

	return tenderApproval, nil
}

// UpdateTenderApprovalWithTender updates a tender approval and returns it with tender details
func (s *tenderApprovalService) UpdateTenderApprovalWithTender(ctx context.Context, id string, form *UpdateTenderApprovalForm) (*TenderApprovalWithTenderResponse, error) {
	// Get existing tender approval
	tenderApproval, err := s.repository.GetByID(ctx, id)
	if err != nil {
		s.logger.Error("Failed to get tender approval for update", map[string]interface{}{
			"error":              err.Error(),
			"tender_approval_id": id,
		})
		return nil, errors.New("tender approval not found")
	}

	// Update fields if provided
	if form.SubmissionMode != nil {
		tenderApproval.SubmissionMode = SubmissionMode(*form.SubmissionMode)
	}

	if form.Status != nil {
		tenderApproval.Status = ApprovalStatus(*form.Status)
	}

	// Set updated timestamp
	tenderApproval.UpdatedAt = time.Now().Unix()

	// Update in database
	err = s.repository.Update(ctx, tenderApproval)
	if err != nil {
		s.logger.Error("Failed to update tender approval", map[string]interface{}{
			"error":              err.Error(),
			"tender_approval_id": id,
		})
		return nil, errors.New("failed to update tender approval")
	}

	// Get tender details
	tenderResponse, err := s.tenderService.GetTenderByID(ctx, tenderApproval.TenderID)
	if err != nil {
		s.logger.Warn("Failed to get tender details", map[string]interface{}{
			"tender_id": tenderApproval.TenderID,
			"error":     err.Error(),
		})
		// Return approval without tender details rather than failing completely
		return tenderApproval.ToResponseWithTender(nil), nil
	}

	// Convert tender response to tender details
	tenderDetails := &TenderDetails{
		ID:                  tenderResponse.ID,
		NoticePublicationID: tenderResponse.NoticePublicationID,
		PublicationDate:     tenderResponse.PublicationDate,
		Title:               tenderResponse.Title,
		Description:         tenderResponse.Description,
		ProcurementTypeCode: tenderResponse.ProcurementTypeCode,
		ProcedureCode:       tenderResponse.ProcedureCode,
		EstimatedValue:      tenderResponse.EstimatedValue,
		Currency:            tenderResponse.Currency,
		Duration:            tenderResponse.Duration,
		DurationUnit:        tenderResponse.DurationUnit,
		TenderDeadline:      tenderResponse.TenderDeadline,
		SubmissionDeadline:  tenderResponse.SubmissionDeadline,
		CountryCode:         tenderResponse.CountryCode,
		BuyerOrganization:   &OrganizationResponse{Name: tenderResponse.BuyerOrganization.Name},
		Status:              string(tenderResponse.Status),
	}

	s.logger.Info("Tender approval updated successfully", map[string]interface{}{
		"tender_approval_id": tenderApproval.ID,
		"tender_id":          tenderApproval.TenderID,
		"company_id":         tenderApproval.CompanyID,
	})

	return tenderApproval.ToResponseWithTender(tenderDetails), nil
}

// DeleteTenderApproval deletes a tender approval
func (s *tenderApprovalService) DeleteTenderApproval(ctx context.Context, id string) error {
	// Get tender approval to check if exists
	tenderApproval, err := s.repository.GetByID(ctx, id)
	if err != nil {
		return errors.New("tender approval not found")
	}

	// Delete tender approval
	err = s.repository.Delete(ctx, id)
	if err != nil {
		s.logger.Error("Failed to delete tender approval", map[string]interface{}{
			"error":              err.Error(),
			"tender_approval_id": id,
		})
		return errors.New("failed to delete tender approval")
	}

	s.logger.Info("Tender approval deleted successfully", map[string]interface{}{
		"tender_approval_id": id,
		"tender_id":          tenderApproval.TenderID,
		"company_id":         tenderApproval.CompanyID,
	})

	return nil
}

// ListTenderApprovals lists tender approvals with search and filters
func (s *tenderApprovalService) ListTenderApprovals(ctx context.Context, form *ListTenderApprovalsForm) (*TenderApprovalListResponse, error) {
	// Set defaults
	limit := 20
	if form.Limit != nil {
		limit = *form.Limit
	}

	offset := 0
	if form.Offset != nil {
		offset = *form.Offset
	}

	sortBy := "created_at"
	if form.SortBy != nil {
		sortBy = *form.SortBy
	}

	sortOrder := "desc"
	if form.SortOrder != nil {
		sortOrder = *form.SortOrder
	}

	// Convert status strings to ApprovalStatus
	var status []ApprovalStatus
	if form.Status != nil {
		status = make([]ApprovalStatus, len(form.Status))
		for i, s := range form.Status {
			status[i] = ApprovalStatus(s)
		}
	}

	// Convert submission mode strings to SubmissionMode
	var submissionMode []SubmissionMode
	if form.SubmissionMode != nil {
		submissionMode = make([]SubmissionMode, len(form.SubmissionMode))
		for i, m := range form.SubmissionMode {
			submissionMode[i] = SubmissionMode(m)
		}
	}

	// Get tender approvals
	tenderApprovals, err := s.repository.Search(ctx, form.TenderID, form.CompanyID, status, submissionMode, form.CreatedAtFrom, form.CreatedAtTo, limit, offset, sortBy, sortOrder)
	if err != nil {
		s.logger.Error("Failed to list tender approvals", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, errors.New("failed to list tender approvals")
	}

	// Convert to responses
	var tenderApprovalResponses []*TenderApprovalResponse
	for _, approval := range tenderApprovals {
		tenderApprovalResponses = append(tenderApprovalResponses, approval.ToResponse())
	}

	// TODO: Implement proper count for pagination metadata
	total := int64(len(tenderApprovals)) // This should be a separate count query
	totalPages := (total + int64(limit) - 1) / int64(limit)

	return &TenderApprovalListResponse{
		TenderApprovals: tenderApprovalResponses,
		Total:           total,
		Limit:           limit,
		Offset:          offset,
		TotalPages:      int(totalPages),
	}, nil
}

// SearchTenderApprovals searches tender approvals with advanced filters
func (s *tenderApprovalService) SearchTenderApprovals(ctx context.Context, form *TenderApprovalSearchForm) (*TenderApprovalListResponse, error) {
	// Set defaults
	limit := 20
	if form.Limit != nil {
		limit = *form.Limit
	}

	offset := 0
	if form.Offset != nil {
		offset = *form.Offset
	}

	// Convert status strings to ApprovalStatus
	var status []ApprovalStatus
	if form.Status != nil {
		status = make([]ApprovalStatus, len(form.Status))
		for i, s := range form.Status {
			status[i] = ApprovalStatus(s)
		}
	}

	// Convert submission mode strings to SubmissionMode
	var submissionMode []SubmissionMode
	if form.SubmissionMode != nil {
		submissionMode = make([]SubmissionMode, len(form.SubmissionMode))
		for i, m := range form.SubmissionMode {
			submissionMode[i] = SubmissionMode(m)
		}
	}

	// Get tender approvals using search
	tenderApprovals, err := s.repository.Search(ctx, form.TenderID, form.CompanyID, status, submissionMode, form.CreatedAtFrom, form.CreatedAtTo, limit, offset, "created_at", "desc")
	if err != nil {
		s.logger.Error("Failed to search tender approvals", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, errors.New("failed to search tender approvals")
	}

	// Convert to responses
	var tenderApprovalResponses []*TenderApprovalResponse
	for _, approval := range tenderApprovals {
		tenderApprovalResponses = append(tenderApprovalResponses, approval.ToResponse())
	}

	// TODO: Implement proper count for pagination metadata
	total := int64(len(tenderApprovals)) // This should be a separate count query
	totalPages := (total + int64(limit) - 1) / int64(limit)

	return &TenderApprovalListResponse{
		TenderApprovals: tenderApprovalResponses,
		Total:           total,
		Limit:           limit,
		Offset:          offset,
		TotalPages:      int(totalPages),
	}, nil
}

// SearchTenderApprovalsByCriteria searches tender approvals using search criteria
func (s *tenderApprovalService) SearchTenderApprovalsByCriteria(ctx context.Context, criteria *TenderApprovalSearchCriteria) ([]*TenderApproval, error) {
	tenderApprovals, err := s.repository.SearchByCriteria(ctx, criteria)
	if err != nil {
		s.logger.Error("Failed to search tender approvals by criteria", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, errors.New("failed to search tender approvals by criteria")
	}

	return tenderApprovals, nil
}

// GetTenderApprovalStats returns tender approval statistics
func (s *tenderApprovalService) GetTenderApprovalStats(ctx context.Context) (*TenderApprovalStatsResponse, error) {
	stats, err := s.repository.GetTenderApprovalStats(ctx)
	if err != nil {
		s.logger.Error("Failed to get tender approval stats", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, errors.New("failed to get tender approval statistics")
	}

	return stats, nil
}

// GetMultipleCompanyTenderApprovalStats returns tender approval statistics for multiple companies
func (s *tenderApprovalService) GetMultipleCompanyTenderApprovalStats(ctx context.Context, companyIDs []string) ([]*CompanyTenderApprovalStatsResponse, error) {
	if len(companyIDs) == 0 {
		return []*CompanyTenderApprovalStatsResponse{}, nil
	}

	var allStats []*CompanyTenderApprovalStatsResponse
	for _, companyID := range companyIDs {
		stats, err := s.GetCompanyTenderApprovalStats(ctx, companyID)
		if err != nil {
			s.logger.Warn("Failed to get stats for company", map[string]interface{}{
				"company_id": companyID,
				"error":      err.Error(),
			})
			// Continue with other companies rather than failing completely
			continue
		}
		allStats = append(allStats, stats)
	}

	s.logger.Info("Multiple company tender approval stats retrieved successfully", map[string]interface{}{
		"requested_count": len(companyIDs),
		"retrieved_count": len(allStats),
	})

	return allStats, nil
}

// GetAggregatedCompanyStats returns aggregated statistics across all companies
func (s *tenderApprovalService) GetAggregatedCompanyStats(ctx context.Context) (*AggregatedCompanyStatsResponse, error) {
	// Get general stats first
	generalStats, err := s.GetTenderApprovalStats(ctx)
	if err != nil {
		s.logger.Error("Failed to get general tender approval stats", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, errors.New("failed to get general tender approval statistics")
	}

	// For now, we'll return basic aggregated stats
	// In a real implementation, you might want to get stats for all companies
	// and aggregate them properly
	stats := &AggregatedCompanyStatsResponse{
		TotalCompanies:        1, // This should be calculated from actual company data
		TotalApprovals:        generalStats.TotalApprovals,
		TotalSubmittedTenders: generalStats.SubmittedTenders,
		TotalRejectedTenders:  generalStats.RejectedTenders,
		CompanyStats:          []*CompanyTenderApprovalStatsResponse{}, // Empty for now
		LastUpdated:           time.Now().Unix(),
	}

	s.logger.Info("Aggregated company stats retrieved successfully", map[string]interface{}{
		"total_approvals": stats.TotalApprovals,
		"total_companies": stats.TotalCompanies,
	})

	return stats, nil
}

// GetTenderApprovalsByStatus retrieves tender approvals by status with pagination
func (s *tenderApprovalService) GetTenderApprovalsByStatus(ctx context.Context, status ApprovalStatus, limit, offset int) ([]*TenderApproval, int64, error) {
	// Use search method with status filter
	tenderApprovals, err := s.repository.Search(ctx, nil, nil, []ApprovalStatus{status}, nil, nil, nil, limit, offset, "created_at", "desc")
	if err != nil {
		s.logger.Error("Failed to get tender approvals by status", map[string]interface{}{
			"error":  err.Error(),
			"status": status,
		})
		return nil, 0, errors.New("failed to get tender approvals by status")
	}

	// Get total count
	total, err := s.repository.CountByStatus(ctx, status)
	if err != nil {
		s.logger.Error("Failed to count tender approvals by status", map[string]interface{}{
			"error":  err.Error(),
			"status": status,
		})
		return tenderApprovals, 0, nil // Return approvals even if count fails
	}

	return tenderApprovals, total, nil
}

// GetTenderApprovalsBySubmissionMode retrieves tender approvals by submission mode with pagination
func (s *tenderApprovalService) GetTenderApprovalsBySubmissionMode(ctx context.Context, submissionMode SubmissionMode, limit, offset int) ([]*TenderApproval, int64, error) {
	// Use search method with submission mode filter
	tenderApprovals, err := s.repository.Search(ctx, nil, nil, nil, []SubmissionMode{submissionMode}, nil, nil, limit, offset, "created_at", "desc")
	if err != nil {
		s.logger.Error("Failed to get tender approvals by submission mode", map[string]interface{}{
			"error":           err.Error(),
			"submission_mode": submissionMode,
		})
		return nil, 0, errors.New("failed to get tender approvals by submission mode")
	}

	// Get total count
	total, err := s.repository.CountBySubmissionMode(ctx, submissionMode)
	if err != nil {
		s.logger.Error("Failed to count tender approvals by submission mode", map[string]interface{}{
			"error":           err.Error(),
			"submission_mode": submissionMode,
		})
		return tenderApprovals, 0, nil
	}

	return tenderApprovals, total, nil
}

// GetTenderApprovalsByStatusWithTender retrieves tender approvals by status with tender details
func (s *tenderApprovalService) GetTenderApprovalsByStatusWithTender(ctx context.Context, status ApprovalStatus, limit, offset int) ([]*TenderApprovalWithTenderResponse, int64, error) {
	tenderApprovals, total, err := s.GetTenderApprovalsByStatus(ctx, status, limit, offset)
	if err != nil {
		return nil, 0, err
	}

	// Convert to response with tender details
	var responses []*TenderApprovalWithTenderResponse
	for _, approval := range tenderApprovals {
		// Get tender details
		tenderResponse, err := s.tenderService.GetTenderByID(ctx, approval.TenderID)
		if err != nil {
			s.logger.Warn("Failed to get tender details", map[string]interface{}{
				"tender_id": approval.TenderID,
				"error":     err.Error(),
			})
			// Continue without tender details rather than failing completely
			responses = append(responses, approval.ToResponseWithTender(nil))
			continue
		}

		// Convert tender response to tender details
		tenderDetails := &TenderDetails{
			ID:                  tenderResponse.ID,
			NoticePublicationID: tenderResponse.NoticePublicationID,
			PublicationDate:     tenderResponse.PublicationDate,
			Title:               tenderResponse.Title,
			Description:         tenderResponse.Description,
			ProcurementTypeCode: tenderResponse.ProcurementTypeCode,
			ProcedureCode:       tenderResponse.ProcurementTypeCode,
			EstimatedValue:      tenderResponse.EstimatedValue,
			Currency:            tenderResponse.Currency,
			Duration:            tenderResponse.Duration,
			DurationUnit:        tenderResponse.DurationUnit,
			TenderDeadline:      tenderResponse.TenderDeadline,
			SubmissionDeadline:  tenderResponse.SubmissionDeadline,
			CountryCode:         tenderResponse.CountryCode,
			BuyerOrganization:   &OrganizationResponse{Name: tenderResponse.BuyerOrganization.Name},
			Status:              string(tenderResponse.Status),
		}

		responses = append(responses, approval.ToResponseWithTender(tenderDetails))
	}

	return responses, total, nil
}

// GetTenderApprovalsBySubmissionModeWithTender retrieves tender approvals by submission mode with tender details
func (s *tenderApprovalService) GetTenderApprovalsBySubmissionModeWithTender(ctx context.Context, submissionMode SubmissionMode, limit, offset int) ([]*TenderApprovalWithTenderResponse, int64, error) {
	tenderApprovals, total, err := s.GetTenderApprovalsBySubmissionMode(ctx, submissionMode, limit, offset)
	if err != nil {
		return nil, 0, err
	}

	// Convert to response with tender details
	var responses []*TenderApprovalWithTenderResponse
	for _, approval := range tenderApprovals {
		// Get tender details
		tenderResponse, err := s.tenderService.GetTenderByID(ctx, approval.TenderID)
		if err != nil {
			s.logger.Warn("Failed to get tender details", map[string]interface{}{
				"tender_id": approval.TenderID,
				"error":     err.Error(),
			})
			// Continue without tender details rather than failing completely
			responses = append(responses, approval.ToResponseWithTender(nil))
			continue
		}

		// Convert tender response to tender details
		tenderDetails := &TenderDetails{
			ID:                  tenderResponse.ID,
			NoticePublicationID: tenderResponse.NoticePublicationID,
			PublicationDate:     tenderResponse.PublicationDate,
			Title:               tenderResponse.Title,
			Description:         tenderResponse.Description,
			ProcurementTypeCode: tenderResponse.ProcurementTypeCode,
			ProcedureCode:       tenderResponse.ProcedureCode,
			EstimatedValue:      tenderResponse.EstimatedValue,
			Currency:            tenderResponse.Currency,
			Duration:            tenderResponse.Duration,
			DurationUnit:        tenderResponse.DurationUnit,
			TenderDeadline:      tenderResponse.TenderDeadline,
			SubmissionDeadline:  tenderResponse.SubmissionDeadline,
			CountryCode:         tenderResponse.CountryCode,
			BuyerOrganization:   &OrganizationResponse{Name: tenderResponse.BuyerOrganization.Name},
			Status:              string(tenderResponse.Status),
		}

		responses = append(responses, approval.ToResponseWithTender(tenderDetails))
	}

	return responses, total, nil
}

// ListTenderApprovalsWithTender lists tender approvals with search and filters, including tender details
func (s *tenderApprovalService) ListTenderApprovalsWithTender(ctx context.Context, form *ListTenderApprovalsForm) (*TenderApprovalListResponseWithTender, error) {
	// Set defaults
	limit := 20
	if form.Limit != nil {
		limit = *form.Limit
	}

	offset := 0
	if form.Offset != nil {
		offset = *form.Offset
	}

	sortBy := "created_at"
	if form.SortBy != nil {
		sortBy = *form.SortBy
	}

	sortOrder := "desc"
	if form.SortOrder != nil {
		sortOrder = *form.SortOrder
	}

	// Convert status strings to ApprovalStatus
	var status []ApprovalStatus
	if form.Status != nil {
		for _, s := range form.Status {
			status = append(status, ApprovalStatus(s))
		}
	}

	// Convert submission mode strings to SubmissionMode
	var submissionMode []SubmissionMode
	if form.SubmissionMode != nil {
		for _, sm := range form.SubmissionMode {
			submissionMode = append(submissionMode, SubmissionMode(sm))
		}
	}

	// Search tender approvals
	tenderApprovals, err := s.repository.Search(ctx, form.TenderID, form.CompanyID, status, submissionMode, form.CreatedAtFrom, form.CreatedAtTo, limit, offset, sortBy, sortOrder)
	if err != nil {
		s.logger.Error("Failed to search tender approvals", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, errors.New("failed to search tender approvals")
	}

	// Get total count for pagination
	total, err := s.repository.Count(ctx)
	if err != nil {
		s.logger.Error("Failed to count tender approvals", map[string]interface{}{
			"error": err.Error(),
		})
		total = int64(len(tenderApprovals)) // Use actual count if total count fails
	}

	// Convert to response with tender details
	var responses []*TenderApprovalWithTenderResponse
	for _, approval := range tenderApprovals {
		// Get tender details
		tenderResponse, err := s.tenderService.GetTenderByID(ctx, approval.TenderID)
		if err != nil {
			s.logger.Warn("Failed to get tender details", map[string]interface{}{
				"tender_id": approval.TenderID,
				"error":     err.Error(),
			})
			// Continue without tender details rather than failing completely
			responses = append(responses, approval.ToResponseWithTender(nil))
			continue
		}

		// Convert tender response to tender details
		tenderDetails := &TenderDetails{
			ID:                  tenderResponse.ID,
			NoticePublicationID: tenderResponse.NoticePublicationID,
			PublicationDate:     tenderResponse.PublicationDate,
			Title:               tenderResponse.Title,
			Description:         tenderResponse.Description,
			ProcurementTypeCode: tenderResponse.ProcurementTypeCode,
			ProcedureCode:       tenderResponse.ProcedureCode,
			EstimatedValue:      tenderResponse.EstimatedValue,
			Currency:            tenderResponse.Currency,
			Duration:            tenderResponse.Duration,
			DurationUnit:        tenderResponse.DurationUnit,
			TenderDeadline:      tenderResponse.TenderDeadline,
			SubmissionDeadline:  tenderResponse.SubmissionDeadline,
			CountryCode:         tenderResponse.CountryCode,
			BuyerOrganization:   &OrganizationResponse{Name: tenderResponse.BuyerOrganization.Name},
			Status:              string(tenderResponse.Status),
		}

		responses = append(responses, approval.ToResponseWithTender(tenderDetails))
	}

	// Calculate pagination metadata
	pages := int(total) / limit
	if int(total)%limit > 0 {
		pages++
	}
	page := (offset / limit) + 1

	meta := &TenderApprovalListResponseWithTender{
		TenderApprovals: responses,
		Metadata: &response.Meta{
			Total:  int(total),
			Limit:  limit,
			Offset: offset,
			Page:   page,
			Pages:  pages,
		},
	}

	return meta, nil
}

func (s *tenderApprovalService) ToggleTenderApproval(ctx context.Context, req *ToggleTenderApprovalForm, companyID string) (*TenderApprovalWithTenderResponse, error) {
	existing, err := s.repository.GetByTenderAndCompany(ctx, req.TenderID, companyID)
	if err != nil {
		approval := &TenderApproval{
			TenderID:       req.TenderID,
			CompanyID:      companyID,
			SubmissionMode: req.SubmissionMode,
			Status:         req.Status,
		}

		err = s.repository.Create(ctx, approval)
		if err != nil {
			s.logger.Error("Failed to create new tender approval", map[string]interface{}{
				"tender_id":       req.TenderID,
				"company_id":      companyID,
				"status":          req.Status,
				"submission_mode": req.SubmissionMode,
				"error":           err.Error(),
			})
			return nil, err
		}

		return approval.ToResponseWithTender(nil), nil
	}

	if existing.Status == req.Status {
		err = s.repository.Delete(ctx, existing.GetID())
		if err != nil {
			s.logger.Error("Failed to update tender approval", map[string]interface{}{
				"error": err.Error(),
			})
			return nil, err
		}

		if req.Status == ApprovalStatusSubmitted {
			existing.Status = "unsubmitted"
		} else {
			existing.Status = "unrejected"
		}

		return existing.ToResponseWithTender(nil), nil
	} else if existing.Status == req.Status && existing.SubmissionMode != req.SubmissionMode {
		existing.SubmissionMode = req.SubmissionMode
		err = s.repository.Update(ctx, existing)
		if err != nil {
			s.logger.Error("Failed to update tender approval", map[string]interface{}{
				"error": err.Error(),
			})
			return nil, err
		}

		return existing.ToResponseWithTender(nil), nil
	}

	if existing.Status == ApprovalStatusSubmitted {
		existing.Reject()
	} else {
		existing.Submit()
	}

	err = s.repository.Update(ctx, existing)
	if err != nil {
		s.logger.Error("Failed to update tender approval", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, err
	}

	return existing.ToResponseWithTender(nil), nil
}

// GetCompanyTenderApprovalStats returns company-specific tender approval statistics
func (s *tenderApprovalService) GetCompanyTenderApprovalStats(ctx context.Context, companyID string) (*CompanyTenderApprovalStatsResponse, error) {
	stats, err := s.repository.GetCompanyTenderApprovalStats(ctx, companyID)
	if err != nil {
		s.logger.Error("Failed to get company tender approval stats", map[string]interface{}{
			"error":      err.Error(),
			"company_id": companyID,
		})
		return nil, errors.New("failed to get company tender approval statistics")
	}

	s.logger.Info("Company tender approval stats retrieved successfully", map[string]interface{}{
		"company_id":        companyID,
		"total_approvals":   stats.TotalApprovals,
		"submitted_tenders": stats.SubmittedTenders,
		"rejected_tenders":  stats.RejectedTenders,
		"self_apply_count":  stats.SelfApplyCount,
		"partnership_count": stats.PartnershipCount,
	})

	return stats, nil
}
