package services

import (
	"net/http"
	"testing"

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

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

func setupDocumentService(t *testing.T) (*DocumentService, *repositories.DocumentRepository, *repositories.ResidenceRepository) {
	db := testutil.SetupTestDB(t)
	testutil.SeedLookupData(t, db)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)
	return service, documentRepo, residenceRepo
}

// === CreateDocument ===

func TestDocumentService_CreateDocument(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	req := &requests.CreateDocumentRequest{
		ResidenceID:  residence.ID,
		Title:        "Furnace Manual",
		Description:  "Installation manual for the furnace",
		DocumentType: models.DocumentTypeManual,
		FileURL:      "https://example.com/manual.pdf",
		FileName:     "manual.pdf",
	}

	resp, err := service.CreateDocument(req, user.ID)
	require.NoError(t, err)
	assert.NotNil(t, resp)
	assert.Equal(t, "Furnace Manual", resp.Title)
	assert.Equal(t, models.DocumentTypeManual, resp.DocumentType)
}

func TestDocumentService_CreateDocument_DefaultType(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	req := &requests.CreateDocumentRequest{
		ResidenceID: residence.ID,
		Title:       "Some Document",
		// DocumentType not set — should default to "general"
	}

	resp, err := service.CreateDocument(req, user.ID)
	require.NoError(t, err)
	assert.Equal(t, models.DocumentTypeGeneral, resp.DocumentType)
}

func TestDocumentService_CreateDocument_WithImages(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	req := &requests.CreateDocumentRequest{
		ResidenceID: residence.ID,
		Title:       "Receipt with photos",
		ImageURLs:   []string{"https://example.com/img1.jpg", "https://example.com/img2.jpg"},
	}

	resp, err := service.CreateDocument(req, user.ID)
	require.NoError(t, err)
	assert.NotNil(t, resp)
	assert.Equal(t, "Receipt with photos", resp.Title)
}

func TestDocumentService_CreateDocument_AccessDenied(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	req := &requests.CreateDocumentRequest{
		ResidenceID: residence.ID,
		Title:       "Unauthorized Doc",
	}

	_, err := service.CreateDocument(req, other.ID)
	testutil.AssertAppError(t, err, http.StatusForbidden, "error.residence_access_denied")
}

// === GetDocument ===

func TestDocumentService_GetDocument(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	resp, err := service.GetDocument(doc.ID, user.ID)
	require.NoError(t, err)
	assert.Equal(t, doc.ID, resp.ID)
	assert.Equal(t, "Test Doc", resp.Title)
}

func TestDocumentService_GetDocument_NotFound(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")

	_, err := service.GetDocument(9999, user.ID)
	testutil.AssertAppError(t, err, http.StatusNotFound, "error.document_not_found")
}

func TestDocumentService_GetDocument_AccessDenied(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	owner := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	other := testutil.CreateTestUser(t, db, "other", "other@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, owner.ID, "Test House")
	doc := testutil.CreateTestDocument(t, db, residence.ID, owner.ID, "Private Doc")

	_, err := service.GetDocument(doc.ID, other.ID)
	testutil.AssertAppError(t, err, http.StatusForbidden, "error.document_access_denied")
}

// === UpdateDocument ===

func TestDocumentService_UpdateDocument(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	newTitle := "Updated Title"
	newDesc := "Updated description"
	req := &requests.UpdateDocumentRequest{
		Title:       &newTitle,
		Description: &newDesc,
	}

	resp, err := service.UpdateDocument(doc.ID, user.ID, req)
	require.NoError(t, err)
	assert.Equal(t, "Updated Title", resp.Title)
	assert.Equal(t, "Updated description", resp.Description)
}

func TestDocumentService_UpdateDocument_NotFound(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")

	newTitle := "Won't Work"
	req := &requests.UpdateDocumentRequest{Title: &newTitle}

	_, err := service.UpdateDocument(9999, user.ID, req)
	testutil.AssertAppError(t, err, http.StatusNotFound, "error.document_not_found")
}

func TestDocumentService_UpdateDocument_AccessDenied(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	owner := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	other := testutil.CreateTestUser(t, db, "other", "other@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, owner.ID, "Test House")
	doc := testutil.CreateTestDocument(t, db, residence.ID, owner.ID, "Private Doc")

	newTitle := "Hacked"
	req := &requests.UpdateDocumentRequest{Title: &newTitle}

	_, err := service.UpdateDocument(doc.ID, other.ID, req)
	testutil.AssertAppError(t, err, http.StatusForbidden, "error.document_access_denied")
}

func TestDocumentService_UpdateDocument_ChangeType(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	newType := models.DocumentTypeWarranty
	req := &requests.UpdateDocumentRequest{DocumentType: &newType}

	resp, err := service.UpdateDocument(doc.ID, user.ID, req)
	require.NoError(t, err)
	assert.Equal(t, models.DocumentTypeWarranty, resp.DocumentType)
}

// === DeleteDocument ===

func TestDocumentService_DeleteDocument(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	err := service.DeleteDocument(doc.ID, user.ID)
	require.NoError(t, err)

	// Should not be found after deletion
	_, err = service.GetDocument(doc.ID, user.ID)
	assert.Error(t, err)
}

func TestDocumentService_DeleteDocument_NotFound(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")

	err := service.DeleteDocument(9999, user.ID)
	testutil.AssertAppError(t, err, http.StatusNotFound, "error.document_not_found")
}

func TestDocumentService_DeleteDocument_AccessDenied(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	owner := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	other := testutil.CreateTestUser(t, db, "other", "other@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, owner.ID, "Test House")
	doc := testutil.CreateTestDocument(t, db, residence.ID, owner.ID, "Private Doc")

	err := service.DeleteDocument(doc.ID, other.ID)
	testutil.AssertAppError(t, err, http.StatusForbidden, "error.document_access_denied")
}

// === ListDocuments ===

func TestDocumentService_ListDocuments(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	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, "Doc 1")
	testutil.CreateTestDocument(t, db, residence.ID, user.ID, "Doc 2")

	resp, err := service.ListDocuments(user.ID, nil)
	require.NoError(t, err)
	assert.Len(t, resp, 2)
}

func TestDocumentService_ListDocuments_NoResidences(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	user := testutil.CreateTestUser(t, db, "loner", "loner@test.com", "Password123")

	resp, err := service.ListDocuments(user.ID, nil)
	require.NoError(t, err)
	assert.Empty(t, resp)
}

func TestDocumentService_ListDocuments_FilterByResidence(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence1 := testutil.CreateTestResidence(t, db, user.ID, "House 1")
	residence2 := testutil.CreateTestResidence(t, db, user.ID, "House 2")
	testutil.CreateTestDocument(t, db, residence1.ID, user.ID, "Doc A")
	testutil.CreateTestDocument(t, db, residence2.ID, user.ID, "Doc B")

	filter := &repositories.DocumentFilter{ResidenceID: &residence1.ID}
	resp, err := service.ListDocuments(user.ID, filter)
	require.NoError(t, err)
	assert.Len(t, resp, 1)
	assert.Equal(t, "Doc A", resp[0].Title)
}

func TestDocumentService_ListDocuments_FilterByResidence_AccessDenied(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	owner := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	other := testutil.CreateTestUser(t, db, "other", "other@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, owner.ID, "Owner House")
	// other has their own residence so they have at least one
	testutil.CreateTestResidence(t, db, other.ID, "Other House")

	filter := &repositories.DocumentFilter{ResidenceID: &residence.ID}
	_, err := service.ListDocuments(other.ID, filter)
	testutil.AssertAppError(t, err, http.StatusForbidden, "error.residence_access_denied")
}

// === ListWarranties ===

func TestDocumentService_ListWarranties(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	// Create a warranty doc directly
	warrantyDoc := &models.Document{
		ResidenceID:  residence.ID,
		CreatedByID:  user.ID,
		Title:        "HVAC Warranty",
		DocumentType: "warranty",
		FileURL:      "https://example.com/warranty.pdf",
	}
	err := db.Create(warrantyDoc).Error
	require.NoError(t, err)

	// Create a general doc
	testutil.CreateTestDocument(t, db, residence.ID, user.ID, "General Doc")

	resp, err := service.ListWarranties(user.ID)
	require.NoError(t, err)
	assert.Len(t, resp, 1)
	assert.Equal(t, "HVAC Warranty", resp[0].Title)
}

func TestDocumentService_ListWarranties_NoResidences(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	user := testutil.CreateTestUser(t, db, "loner", "loner@test.com", "Password123")

	resp, err := service.ListWarranties(user.ID)
	require.NoError(t, err)
	assert.Empty(t, resp)
}

// === DeactivateDocument ===

func TestDocumentService_DeactivateDocument(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	resp, err := service.DeactivateDocument(doc.ID, user.ID)
	require.NoError(t, err)
	assert.False(t, resp.IsActive)
}

func TestDocumentService_DeactivateDocument_NotFound(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")

	_, err := service.DeactivateDocument(9999, user.ID)
	testutil.AssertAppError(t, err, http.StatusNotFound, "error.document_not_found")
}

func TestDocumentService_DeactivateDocument_AccessDenied(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	owner := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	other := testutil.CreateTestUser(t, db, "other", "other@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, owner.ID, "Test House")
	doc := testutil.CreateTestDocument(t, db, residence.ID, owner.ID, "Private Doc")

	_, err := service.DeactivateDocument(doc.ID, other.ID)
	testutil.AssertAppError(t, err, http.StatusForbidden, "error.document_access_denied")
}

// === UploadDocumentImage ===

func TestDocumentService_UploadDocumentImage(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	resp, err := service.UploadDocumentImage(doc.ID, user.ID, "https://example.com/photo.jpg", "Front view")
	require.NoError(t, err)
	assert.NotNil(t, resp)
}

func TestDocumentService_UploadDocumentImage_NotFound(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")

	_, err := service.UploadDocumentImage(9999, user.ID, "https://example.com/photo.jpg", "")
	testutil.AssertAppError(t, err, http.StatusNotFound, "error.document_not_found")
}

func TestDocumentService_UploadDocumentImage_AccessDenied(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	owner := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	other := testutil.CreateTestUser(t, db, "other", "other@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, owner.ID, "Test House")
	doc := testutil.CreateTestDocument(t, db, residence.ID, owner.ID, "Private Doc")

	_, err := service.UploadDocumentImage(doc.ID, other.ID, "https://example.com/photo.jpg", "")
	testutil.AssertAppError(t, err, http.StatusForbidden, "error.document_access_denied")
}

// === DeleteDocumentImage ===

func TestDocumentService_DeleteDocumentImage(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	// Create an image
	img := &models.DocumentImage{
		DocumentID: doc.ID,
		ImageURL:   "https://example.com/photo.jpg",
	}
	err := db.Create(img).Error
	require.NoError(t, err)

	resp, err := service.DeleteDocumentImage(doc.ID, img.ID, user.ID)
	require.NoError(t, err)
	assert.NotNil(t, resp)
}

func TestDocumentService_DeleteDocumentImage_NotFound(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	_, err := service.DeleteDocumentImage(doc.ID, 9999, user.ID)
	testutil.AssertAppError(t, err, http.StatusNotFound, "error.document_image_not_found")
}

func TestDocumentService_DeleteDocumentImage_WrongDocument(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")
	doc1 := testutil.CreateTestDocument(t, db, residence.ID, user.ID, "Doc 1")
	doc2 := testutil.CreateTestDocument(t, db, residence.ID, user.ID, "Doc 2")

	// Create an image on doc1
	img := &models.DocumentImage{
		DocumentID: doc1.ID,
		ImageURL:   "https://example.com/photo.jpg",
	}
	err := db.Create(img).Error
	require.NoError(t, err)

	// Try to delete the image specifying doc2
	_, err = service.DeleteDocumentImage(doc2.ID, img.ID, user.ID)
	testutil.AssertAppError(t, err, http.StatusNotFound, "error.document_image_not_found")
}

func TestDocumentService_DeleteDocumentImage_AccessDenied(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	owner := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	other := testutil.CreateTestUser(t, db, "other", "other@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, owner.ID, "Test House")
	doc := testutil.CreateTestDocument(t, db, residence.ID, owner.ID, "Private Doc")

	img := &models.DocumentImage{
		DocumentID: doc.ID,
		ImageURL:   "https://example.com/photo.jpg",
	}
	err := db.Create(img).Error
	require.NoError(t, err)

	_, err = service.DeleteDocumentImage(doc.ID, img.ID, other.ID)
	testutil.AssertAppError(t, err, http.StatusForbidden, "error.document_access_denied")
}

// === SharedUser access ===

func TestDocumentService_GetDocument_SharedUserHasAccess(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	owner := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	shared := testutil.CreateTestUser(t, db, "shared", "shared@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, owner.ID, "Test House")
	residenceRepo.AddUser(residence.ID, shared.ID)
	doc := testutil.CreateTestDocument(t, db, residence.ID, owner.ID, "Shared Doc")

	resp, err := service.GetDocument(doc.ID, shared.ID)
	require.NoError(t, err)
	assert.Equal(t, "Shared Doc", resp.Title)
}

// === ActivateDocument ===

func TestDocumentService_ActivateDocument(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	// Deactivate first
	_, err := service.DeactivateDocument(doc.ID, user.ID)
	require.NoError(t, err)

	// Now activate
	resp, err := service.ActivateDocument(doc.ID, user.ID)
	require.NoError(t, err)
	assert.True(t, resp.IsActive)
}

func TestDocumentService_ActivateDocument_NotFound(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")

	_, err := service.ActivateDocument(9999, user.ID)
	testutil.AssertAppError(t, err, http.StatusNotFound, "error.document_not_found")
}

func TestDocumentService_ActivateDocument_AccessDenied(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	owner := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	other := testutil.CreateTestUser(t, db, "other", "other@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, owner.ID, "Test House")
	doc := testutil.CreateTestDocument(t, db, residence.ID, owner.ID, "Private Doc")

	_, err := service.ActivateDocument(doc.ID, other.ID)
	testutil.AssertAppError(t, err, http.StatusForbidden, "error.document_access_denied")
}

// === CreateDocument — with empty image URL in array (should skip) ===

func TestDocumentService_CreateDocument_WithEmptyImageURL(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	req := &requests.CreateDocumentRequest{
		ResidenceID: residence.ID,
		Title:       "Doc with empty images",
		ImageURLs:   []string{"", "https://example.com/img.jpg", ""},
	}

	resp, err := service.CreateDocument(req, user.ID)
	require.NoError(t, err)
	assert.NotNil(t, resp)
}

// === UpdateDocument — all optional fields ===

func TestDocumentService_UpdateDocument_AllFields(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	newTitle := "Updated"
	newDesc := "New description"
	newType := models.DocumentTypeWarranty
	newFileURL := "https://example.com/new.pdf"
	newFileName := "new.pdf"
	newMimeType := "application/pdf"
	newVendor := "HVAC Corp"
	newSerial := "SN12345"
	newModel := "Model X"
	size := int64(1024)

	req := &requests.UpdateDocumentRequest{
		Title:        &newTitle,
		Description:  &newDesc,
		DocumentType: &newType,
		FileURL:      &newFileURL,
		FileName:     &newFileName,
		FileSize:     &size,
		MimeType:     &newMimeType,
		Vendor:       &newVendor,
		SerialNumber: &newSerial,
		ModelNumber:  &newModel,
	}

	resp, err := service.UpdateDocument(doc.ID, user.ID, req)
	require.NoError(t, err)
	assert.Equal(t, "Updated", resp.Title)
	assert.Equal(t, "New description", resp.Description)
	assert.Equal(t, models.DocumentTypeWarranty, resp.DocumentType)
}

// === ListDocuments — filter by document type ===

func TestDocumentService_ListDocuments_FilterByType(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

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

	// Create a warranty doc
	warrantyDoc := &models.Document{
		ResidenceID:  residence.ID,
		CreatedByID:  user.ID,
		Title:        "Warranty Doc",
		DocumentType: models.DocumentTypeWarranty,
		FileURL:      "https://example.com/w.pdf",
	}
	err := db.Create(warrantyDoc).Error
	require.NoError(t, err)

	// Create a general doc
	testutil.CreateTestDocument(t, db, residence.ID, user.ID, "General Doc")

	filter := &repositories.DocumentFilter{DocumentType: string(models.DocumentTypeWarranty)}
	resp, err := service.ListDocuments(user.ID, filter)
	require.NoError(t, err)
	assert.Len(t, resp, 1)
	assert.Equal(t, "Warranty Doc", resp[0].Title)
}

// === Shared user can update/delete documents ===

func TestDocumentService_SharedUser_CanUpdate(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	owner := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	shared := testutil.CreateTestUser(t, db, "shared", "shared@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, owner.ID, "Test House")
	residenceRepo.AddUser(residence.ID, shared.ID)
	doc := testutil.CreateTestDocument(t, db, residence.ID, owner.ID, "Shared Doc")

	newTitle := "Updated by shared user"
	req := &requests.UpdateDocumentRequest{Title: &newTitle}
	resp, err := service.UpdateDocument(doc.ID, shared.ID, req)
	require.NoError(t, err)
	assert.Equal(t, "Updated by shared user", resp.Title)
}

func TestDocumentService_SharedUser_CanDelete(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	service := NewDocumentService(documentRepo, residenceRepo)

	owner := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	shared := testutil.CreateTestUser(t, db, "shared", "shared@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, owner.ID, "Test House")
	residenceRepo.AddUser(residence.ID, shared.ID)
	doc := testutil.CreateTestDocument(t, db, residence.ID, owner.ID, "Shared Doc")

	err := service.DeleteDocument(doc.ID, shared.ID)
	require.NoError(t, err)
}
