package deletion

import (
	"fmt"

	"git.kirsle.net/apps/gosocial/pkg/log"
	"git.kirsle.net/apps/gosocial/pkg/models"
	"git.kirsle.net/apps/gosocial/pkg/photo"
)

// DeleteUser wipes a user and all associated data from the database.
func DeleteUser(user *models.User) error {
	log.Error("BEGIN DeleteUser(%d, %s)", user.ID, user.Username)

	// Remove all linked tables and assets.
	type remover struct {
		Step string
		Fn   func(uint64) error
	}

	var todo = []remover{
		{"Photos", DeleteUserPhotos},
		{"Certification Photo", DeleteCertification},
		{"Messages", DeleteUserMessages},
		{"Friends", DeleteFriends},
		{"Profile Fields", DeleteProfile},
	}
	for _, item := range todo {
		if err := item.Fn(user.ID); err != nil {
			return fmt.Errorf("%s: %s", item.Step, err)
		}
	}

	// Remove the user itself.
	return user.Delete()
}

// DeleteUserPhotos scrubs data for deleting a user.
func DeleteUserPhotos(userID uint64) error {
	log.Error("DeleteUser: BEGIN DeleteUserPhotos(%d)", userID)

	// Deeply scrub all user photos.
	pager := &models.Pagination{
		Page:    1,
		PerPage: 20,
		Sort:    "photos.id",
	}

	for {
		photos, err := models.PaginateUserPhotos(
			userID,
			models.PhotoVisibilityAll,
			true,
			pager,
		)

		if err != nil {
			return err
		}

		if len(photos) == 0 {
			break
		}

		for _, item := range photos {
			log.Warn("DeleteUserPhotos(%d): remove file %s", userID, item.Filename)
			photo.Delete(item.Filename)
			if item.CroppedFilename != "" {
				log.Warn("DeleteUserPhotos(%d): remove file %s", userID, item.CroppedFilename)
				photo.Delete(item.CroppedFilename)
			}
			if err := item.Delete(); err != nil {
				return err
			}
		}
	}

	log.Error("DeleteUser: END DeleteUserPhotos(%d)", userID)
	return nil
}

// DeleteCertification scrubs data for deleting a user.
func DeleteCertification(userID uint64) error {
	log.Error("DeleteUser: DeleteCertification(%d)", userID)
	if cert, err := models.GetCertificationPhoto(userID); err == nil {
		if cert.Filename != "" {
			log.Warn("DeleteCertification(%d): remove file %s", userID, cert.Filename)
			photo.Delete(cert.Filename)
		}
		return cert.Delete()
	}
	return nil
}

// DeleteUserMessages scrubs data for deleting a user.
func DeleteUserMessages(userID uint64) error {
	log.Error("DeleteUser: DeleteUserMessages(%d)", userID)
	result := models.DB.Where(
		"source_user_id = ? OR target_user_id = ?",
		userID, userID,
	).Delete(&models.Message{})
	return result.Error
}

// DeleteFriends scrubs data for deleting a user.
func DeleteFriends(userID uint64) error {
	log.Error("DeleteUser: DeleteUserFriends(%d)", userID)
	result := models.DB.Where(
		"source_user_id = ? OR target_user_id = ?",
		userID, userID,
	).Delete(&models.Friend{})
	return result.Error
}

// DeleteProfile scrubs data for deleting a user.
func DeleteProfile(userID uint64) error {
	log.Error("DeleteUser: DeleteProfile(%d)", userID)
	result := models.DB.Where(
		"user_id = ?",
		userID,
	).Delete(&models.ProfileField{})
	return result.Error
}
