// internal/repositories/match_result_repo.go
package repositories

import (
	"errors"
	"lost-and-found/internal/models"

	"gorm.io/gorm"
)

type MatchResultRepository struct {
	db *gorm.DB
}

func NewMatchResultRepository(db *gorm.DB) *MatchResultRepository {
	return &MatchResultRepository{db: db}
}

// Create creates a new match result
func (r *MatchResultRepository) Create(match *models.MatchResult) error {
	return r.db.Create(match).Error
}

// FindByID finds match result by ID
func (r *MatchResultRepository) FindByID(id uint) (*models.MatchResult, error) {
	var match models.MatchResult
	err := r.db.Preload("LostItem").Preload("LostItem.User").
		Preload("Item").Preload("Item.Category").
		First(&match, id).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("match result not found")
		}
		return nil, err
	}
	return &match, nil
}

// FindAll returns all match results with filters
func (r *MatchResultRepository) FindAll(page, limit int, lostItemID, itemID *uint) ([]models.MatchResult, int64, error) {
	var matches []models.MatchResult
	var total int64

	query := r.db.Model(&models.MatchResult{})

	// Apply filters
	if lostItemID != nil {
		query = query.Where("lost_item_id = ?", *lostItemID)
	}
	if itemID != nil {
		query = query.Where("item_id = ?", *itemID)
	}

	// Count total
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// Get paginated results
	offset := (page - 1) * limit
	err := query.Preload("LostItem").Preload("LostItem.User").
		Preload("Item").Preload("Item.Category").
		Order("similarity_score DESC").
		Offset(offset).Limit(limit).Find(&matches).Error
	if err != nil {
		return nil, 0, err
	}

	return matches, total, nil
}

// FindByLostItem finds match results for a lost item
func (r *MatchResultRepository) FindByLostItem(lostItemID uint) ([]models.MatchResult, error) {
	var matches []models.MatchResult
	err := r.db.Where("lost_item_id = ?", lostItemID).
		Preload("Item").Preload("Item.Category").
		Order("similarity_score DESC").Find(&matches).Error
	return matches, err
}

// FindByItem finds match results for an item
func (r *MatchResultRepository) FindByItem(itemID uint) ([]models.MatchResult, error) {
	var matches []models.MatchResult
	err := r.db.Where("item_id = ?", itemID).
		Preload("LostItem").Preload("LostItem.User").
		Order("similarity_score DESC").Find(&matches).Error
	return matches, err
}

// Update updates match result
func (r *MatchResultRepository) Update(match *models.MatchResult) error {
	return r.db.Save(match).Error
}

// MarkAsNotified marks match result as notified
func (r *MatchResultRepository) MarkAsNotified(id uint) error {
	return r.db.Model(&models.MatchResult{}).Where("id = ?", id).Update("is_notified", true).Error
}

// FindUnnotifiedMatches finds match results that haven't been notified
func (r *MatchResultRepository) FindUnnotifiedMatches() ([]models.MatchResult, error) {
	var matches []models.MatchResult
	err := r.db.Where("is_notified = ?", false).
		Preload("LostItem").Preload("LostItem.User").
		Preload("Item").Preload("Item.Category").
		Order("matched_at ASC").Find(&matches).Error
	return matches, err
}

// Delete deletes a match result
func (r *MatchResultRepository) Delete(id uint) error {
	return r.db.Delete(&models.MatchResult{}, id).Error
}

// CheckExistingMatch checks if a match already exists
func (r *MatchResultRepository) CheckExistingMatch(lostItemID, itemID uint) (bool, error) {
	var count int64
	err := r.db.Model(&models.MatchResult{}).
		Where("lost_item_id = ? AND item_id = ?", lostItemID, itemID).
		Count(&count).Error
	if err != nil {
		return false, err
	}
	return count > 0, nil
}