package repositories

import (
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/treytartt/honeydue-api/internal/models"
	"github.com/treytartt/honeydue-api/internal/testutil"
)

func TestDocumentRepository_FindExpiringWarranties(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewDocumentRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")

	now := time.Now().UTC()
	expiringSoon := now.AddDate(0, 0, 15) // 15 days from now
	expiringLater := now.AddDate(0, 0, 60) // 60 days from now
	alreadyExpired := now.AddDate(0, 0, -5) // 5 days ago

	// Warranty expiring in 15 days (within 30 day threshold)
	w1 := &models.Document{
		ResidenceID:  residence.ID,
		CreatedByID:  user.ID,
		Title:        "Expiring Warranty",
		DocumentType: models.DocumentTypeWarranty,
		FileURL:      "https://example.com/w1.pdf",
		ExpiryDate:   &expiringSoon,
		IsActive:     true,
	}
	require.NoError(t, db.Create(w1).Error)

	// Warranty expiring in 60 days (outside 30 day threshold)
	w2 := &models.Document{
		ResidenceID:  residence.ID,
		CreatedByID:  user.ID,
		Title:        "Later Warranty",
		DocumentType: models.DocumentTypeWarranty,
		FileURL:      "https://example.com/w2.pdf",
		ExpiryDate:   &expiringLater,
		IsActive:     true,
	}
	require.NoError(t, db.Create(w2).Error)

	// Already expired warranty
	w3 := &models.Document{
		ResidenceID:  residence.ID,
		CreatedByID:  user.ID,
		Title:        "Expired Warranty",
		DocumentType: models.DocumentTypeWarranty,
		FileURL:      "https://example.com/w3.pdf",
		ExpiryDate:   &alreadyExpired,
		IsActive:     true,
	}
	require.NoError(t, db.Create(w3).Error)

	// General document (not warranty)
	testutil.CreateTestDocument(t, db, residence.ID, user.ID, "General Doc")

	docs, err := repo.FindExpiringWarranties([]uint{residence.ID}, 30)
	require.NoError(t, err)
	assert.Len(t, docs, 1)
	assert.Equal(t, "Expiring Warranty", docs[0].Title)
}

func TestDocumentRepository_FindByUserFiltered_Search(t *testing.T) {
	t.Skip("requires PostgreSQL: SQLite does not support ILIKE")
	db := testutil.SetupTestDB(t)
	repo := NewDocumentRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")

	d1 := &models.Document{
		ResidenceID:  residence.ID,
		CreatedByID:  user.ID,
		Title:        "HVAC Warranty Certificate",
		Description:  "For the main HVAC unit",
		DocumentType: models.DocumentTypeWarranty,
		FileURL:      "https://example.com/hvac.pdf",
		IsActive:     true,
	}
	require.NoError(t, db.Create(d1).Error)

	d2 := &models.Document{
		ResidenceID:  residence.ID,
		CreatedByID:  user.ID,
		Title:        "Plumbing Receipt",
		Description:  "Bathroom plumbing fix",
		DocumentType: models.DocumentTypeReceipt,
		FileURL:      "https://example.com/plumbing.pdf",
		IsActive:     true,
	}
	require.NoError(t, db.Create(d2).Error)

	// Search by title
	filter := &DocumentFilter{Search: "HVAC"}
	docs, err := repo.FindByUserFiltered([]uint{residence.ID}, filter)
	require.NoError(t, err)
	assert.Len(t, docs, 1)
	assert.Equal(t, "HVAC Warranty Certificate", docs[0].Title)

	// Search by description
	filter = &DocumentFilter{Search: "bathroom"}
	docs, err = repo.FindByUserFiltered([]uint{residence.ID}, filter)
	require.NoError(t, err)
	assert.Len(t, docs, 1)
	assert.Equal(t, "Plumbing Receipt", docs[0].Title)
}

func TestDocumentRepository_FindByUserFiltered_IsActiveOverride(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewDocumentRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")

	active := testutil.CreateTestDocument(t, db, residence.ID, user.ID, "Active Doc")
	inactive := testutil.CreateTestDocument(t, db, residence.ID, user.ID, "Inactive Doc")
	db.Model(&models.Document{}).Where("id = ?", inactive.ID).Update("is_active", false)

	// With IsActive = false, should get only inactive
	isActiveFalse := false
	filter := &DocumentFilter{IsActive: &isActiveFalse}
	docs, err := repo.FindByUserFiltered([]uint{residence.ID}, filter)
	require.NoError(t, err)
	assert.Len(t, docs, 1)
	assert.Equal(t, inactive.ID, docs[0].ID)

	// With IsActive = true, should get only active
	isActiveTrue := true
	filter = &DocumentFilter{IsActive: &isActiveTrue}
	docs, err = repo.FindByUserFiltered([]uint{residence.ID}, filter)
	require.NoError(t, err)
	assert.Len(t, docs, 1)
	assert.Equal(t, active.ID, docs[0].ID)
}

func TestDocumentRepository_FindByUserFiltered_ExpiringSoon(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewDocumentRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")

	now := time.Now().UTC()
	expiringSoon := now.AddDate(0, 0, 10)
	notExpiring := now.AddDate(0, 0, 90)

	d1 := &models.Document{
		ResidenceID:  residence.ID,
		CreatedByID:  user.ID,
		Title:        "Expiring Doc",
		DocumentType: models.DocumentTypeWarranty,
		FileURL:      "https://example.com/exp.pdf",
		ExpiryDate:   &expiringSoon,
		IsActive:     true,
	}
	require.NoError(t, db.Create(d1).Error)

	d2 := &models.Document{
		ResidenceID:  residence.ID,
		CreatedByID:  user.ID,
		Title:        "Not Expiring Doc",
		DocumentType: models.DocumentTypeWarranty,
		FileURL:      "https://example.com/noexp.pdf",
		ExpiryDate:   &notExpiring,
		IsActive:     true,
	}
	require.NoError(t, db.Create(d2).Error)

	days := 30
	filter := &DocumentFilter{ExpiringSoon: &days}
	docs, err := repo.FindByUserFiltered([]uint{residence.ID}, filter)
	require.NoError(t, err)
	assert.Len(t, docs, 1)
	assert.Equal(t, "Expiring Doc", docs[0].Title)
}

func TestDocumentRepository_FindImageByID_NotFound(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewDocumentRepository(db)

	_, err := repo.FindImageByID(9999)
	assert.Error(t, err)
}

func TestDocumentRepository_FindByUser_ExcludesInactive(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewDocumentRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")

	testutil.CreateTestDocument(t, db, residence.ID, user.ID, "Active Doc")
	inactive := testutil.CreateTestDocument(t, db, residence.ID, user.ID, "Inactive Doc")
	db.Model(&models.Document{}).Where("id = ?", inactive.ID).Update("is_active", false)

	docs, err := repo.FindByUser([]uint{residence.ID})
	require.NoError(t, err)
	assert.Len(t, docs, 1)
}
