// internal/repositories/lost_item_repo.go
package repositories

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

	"gorm.io/gorm"
)

type LostItemRepository struct {
	db *gorm.DB
}

func NewLostItemRepository(db *gorm.DB) *LostItemRepository {
	return &LostItemRepository{db: db}
}

// Create creates a new lost item report
func (r *LostItemRepository) Create(lostItem *models.LostItem) error {
	return r.db.Create(lostItem).Error
}

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

// ✅ NEW: FindByMatchedItemID (Dibutuhkan untuk VerifyClaim)
// Mencari lost item yang sudah di-match dengan item tertentu
func (r *LostItemRepository) FindByMatchedItemID(itemID uint) (*models.LostItem, error) {
	var lostItem models.LostItem
	// Asumsi: Anda punya kolom 'matched_item_id' atau logika matching tersimpan
	// Jika logika matching ada di tabel 'match_results', query ini mungkin perlu disesuaikan.
	// Namun, untuk struktur simple, kita cari berdasarkan relasi match
	
	// Jika Anda menggunakan tabel terpisah (MatchResult), method ini mungkin tidak direct di sini,
	// tapi jika LostItem punya field MatchedItemID:
	err := r.db.Where("matched_item_id = ?", itemID).First(&lostItem).Error
	if err != nil {
		return nil, err
	}
	return &lostItem, nil
}

// FindAll returns all lost items with filters
func (r *LostItemRepository) FindAll(page, limit int, status, category, search string, userID *uint) ([]models.LostItem, int64, error) {
	var lostItems []models.LostItem
	var total int64

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

	// Filter by user if specified
	if userID != nil {
		query = query.Where("user_id = ?", *userID)
	}

	// Apply filters
	if status != "" {
		query = query.Where("status = ?", status)
	}
	if category != "" {
		query = query.Joins("JOIN categories ON categories.id = lost_items.category_id").Where("categories.slug = ?", category)
	}
	if search != "" {
		// ✅ FIX: Ganti ILIKE (Postgres) ke LIKE (MySQL Compatible)
		// Jika pakai Postgres, ILIKE boleh dipakai. Jika MySQL, harus LIKE.
		query = query.Where("name LIKE ? OR description LIKE ?", "%"+search+"%", "%"+search+"%")
	}

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

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

	return lostItems, total, nil
}

// Update updates lost item data
func (r *LostItemRepository) Update(lostItem *models.LostItem) error {
	return r.db.Save(lostItem).Error
}

// UpdateStatus updates lost item status
func (r *LostItemRepository) UpdateStatus(id uint, status string) error {
	return r.db.Model(&models.LostItem{}).Where("id = ?", id).Update("status", status).Error
}

// ✅ NEW: UpdateStatusByUserAndCategory (Dibutuhkan untuk CloseCase)
// Mengubah status lost item milik user tertentu di kategori tertentu
// Berguna saat item 'Found' berubah jadi 'Closed'
func (r *LostItemRepository) UpdateStatusByUserAndCategory(userID, categoryID uint, oldStatus, newStatus string) error {
	return r.db.Model(&models.LostItem{}).
		Where("user_id = ? AND category_id = ? AND status = ?", userID, categoryID, oldStatus).
		Update("status", newStatus).Error
}

// Delete soft deletes a lost item
func (r *LostItemRepository) Delete(id uint) error {
	return r.db.Delete(&models.LostItem{}, id).Error
}

// FindByUser finds lost items by user ID
func (r *LostItemRepository) FindByUser(userID uint, page, limit int) ([]models.LostItem, int64, error) {
	var lostItems []models.LostItem
	var total int64

	query := r.db.Model(&models.LostItem{}).Where("user_id = ?", userID)

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

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

	return lostItems, total, nil
}

// CountByStatus counts lost items by status
func (r *LostItemRepository) CountByStatus(status string) (int64, error) {
	var count int64
	err := r.db.Model(&models.LostItem{}).Where("status = ?", status).Count(&count).Error
	return count, err
}

// FindActiveForMatching finds active lost items for matching
func (r *LostItemRepository) FindActiveForMatching(categoryID uint) ([]models.LostItem, error) {
	var lostItems []models.LostItem
	err := r.db.Where("status = ? AND category_id = ?", models.LostItemStatusActive, categoryID).
		Preload("User").Find(&lostItems).Error
	return lostItems, err
}