package repository

import (
	"time"

	"git.mchus.pro/mchus/quoteforge/internal/models"
	"gorm.io/gorm"
)

type ComponentRepository struct {
	db *gorm.DB
}

func NewComponentRepository(db *gorm.DB) *ComponentRepository {
	return &ComponentRepository{db: db}
}

type ComponentFilter struct {
	Category     string
	Search       string
	HasPrice     bool
	ExcludeHidden bool
	SortField    string
	SortDir      string
}

func (r *ComponentRepository) List(filter ComponentFilter, offset, limit int) ([]models.LotMetadata, int64, error) {
	var components []models.LotMetadata
	var total int64

	query := r.db.Model(&models.LotMetadata{}).
		Preload("Lot").
		Preload("Category")

	if filter.Category != "" {
		query = query.Joins("JOIN qt_categories ON qt_lot_metadata.category_id = qt_categories.id").
			Where("qt_categories.code = ?", filter.Category)
	}
	if filter.Search != "" {
		search := "%" + filter.Search + "%"
		query = query.Where("lot_name LIKE ? OR model LIKE ?", search, search)
	}
	if filter.HasPrice {
		query = query.Where("current_price IS NOT NULL AND current_price > 0")
	}
	if filter.ExcludeHidden {
		query = query.Where("is_hidden = ? OR is_hidden IS NULL", false)
	}

	query.Count(&total)

	// Apply sorting
	sortDir := "ASC"
	if filter.SortDir == "desc" {
		sortDir = "DESC"
	}

	switch filter.SortField {
	case "popularity_score":
		query = query.Order("popularity_score " + sortDir)
	case "current_price":
		query = query.Order("CASE WHEN current_price IS NULL OR current_price = 0 THEN 1 ELSE 0 END").
			Order("current_price " + sortDir)
	case "lot_name":
		query = query.Order("lot_name " + sortDir)
	default:
		// Default: sort by popularity, no price goes last
		query = query.
			Order("CASE WHEN current_price IS NULL OR current_price = 0 THEN 1 ELSE 0 END").
			Order("popularity_score DESC")
	}

	err := query.
		Offset(offset).
		Limit(limit).
		Find(&components).Error

	return components, total, err
}

func (r *ComponentRepository) GetByLotName(lotName string) (*models.LotMetadata, error) {
	var component models.LotMetadata
	err := r.db.
		Preload("Lot").
		Preload("Category").
		Where("lot_name = ?", lotName).
		First(&component).Error
	if err != nil {
		return nil, err
	}
	return &component, nil
}

func (r *ComponentRepository) GetMultiple(lotNames []string) ([]models.LotMetadata, error) {
	var components []models.LotMetadata
	err := r.db.
		Preload("Lot").
		Preload("Category").
		Where("lot_name IN ?", lotNames).
		Find(&components).Error
	return components, err
}

func (r *ComponentRepository) Update(component *models.LotMetadata) error {
	return r.db.Save(component).Error
}

func (r *ComponentRepository) DB() *gorm.DB {
	return r.db
}

func (r *ComponentRepository) Create(component *models.LotMetadata) error {
	return r.db.Create(component).Error
}

func (r *ComponentRepository) IncrementRequestCount(lotName string) error {
	now := time.Now()
	return r.db.Model(&models.LotMetadata{}).
		Where("lot_name = ?", lotName).
		Updates(map[string]interface{}{
			"request_count":     gorm.Expr("request_count + 1"),
			"last_request_date": now,
		}).Error
}

// GetAllLots returns all lots from the existing lot table
func (r *ComponentRepository) GetAllLots() ([]models.Lot, error) {
	var lots []models.Lot
	err := r.db.Find(&lots).Error
	return lots, err
}

// GetLotsWithoutMetadata returns lots that don't have qt_lot_metadata entries
func (r *ComponentRepository) GetLotsWithoutMetadata() ([]models.Lot, error) {
	var lots []models.Lot
	err := r.db.
		Where("lot_name NOT IN (SELECT lot_name FROM qt_lot_metadata)").
		Find(&lots).Error
	return lots, err
}
