// monorepo/cloud/backend/internal/service/user/complete_deletion.go
package user

import (
	"context"
	"fmt"
	"time"

	"go.uber.org/zap"

	"github.com/gocql/gocql"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
	svc_collection "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/service/collection"
	svc_file "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/service/file"
	uc_collection "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/usecase/collection"
	uc_filemetadata "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/usecase/filemetadata"
	uc_storagedailyusage "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/usecase/storagedailyusage"
	uc_storageusageevent "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/usecase/storageusageevent"
	uc_user "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/usecase/user"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
)

// CompleteUserDeletionRequest represents a GDPR right-to-be-forgotten deletion request
type CompleteUserDeletionRequest struct {
	UserID   gocql.UUID `json:"user_id"`
	Password string     `json:"password"` // For authentication
}

// DeletionResult contains comprehensive information about the deletion operation
type DeletionResult struct {
	UserID              gocql.UUID `json:"user_id"`
	FilesDeleted        int        `json:"files_deleted"`
	CollectionsDeleted  int        `json:"collections_deleted"`
	S3ObjectsDeleted    int        `json:"s3_objects_deleted"`
	TotalDataSizeBytes  int64      `json:"total_data_size_bytes"`
	MembershipsRemoved  int        `json:"memberships_removed"`
	DeletedAt           time.Time  `json:"deleted_at"`
	Success             bool       `json:"success"`
	Errors              []string   `json:"errors,omitempty"` // Non-fatal errors
}

// CompleteUserDeletionService orchestrates complete GDPR-compliant user deletion
type CompleteUserDeletionService interface {
	Execute(ctx context.Context, req *CompleteUserDeletionRequest) (*DeletionResult, error)
}

type completeUserDeletionServiceImpl struct {
	config                                   *config.Configuration
	logger                                   *zap.Logger
	getUserUseCase                           uc_user.UserGetByIDUseCase
	deleteUserByIDUseCase                    uc_user.UserDeleteByIDUseCase
	listFilesByOwnerIDService                svc_file.ListFilesByOwnerIDService
	softDeleteFileService                    svc_file.SoftDeleteFileService
	listCollectionsByUserUseCase             uc_collection.ListCollectionsByUserUseCase
	softDeleteCollectionService              svc_collection.SoftDeleteCollectionService
	removeUserFromAllCollectionsUseCase      uc_collection.RemoveUserFromAllCollectionsUseCase
	deleteStorageDailyUsageUseCase           uc_storagedailyusage.DeleteByUserUseCase
	deleteStorageUsageEventUseCase           uc_storageusageevent.DeleteByUserUseCase
	anonymizeUserIPsImmediatelyUseCase       uc_user.AnonymizeUserIPsImmediatelyUseCase
	clearUserCacheUseCase                    uc_user.ClearUserCacheUseCase
	anonymizeFileUserReferencesUseCase       uc_filemetadata.AnonymizeUserReferencesUseCase
	anonymizeCollectionUserReferencesUseCase uc_collection.AnonymizeUserReferencesUseCase
}

func NewCompleteUserDeletionService(
	config *config.Configuration,
	logger *zap.Logger,
	getUserUseCase uc_user.UserGetByIDUseCase,
	deleteUserByIDUseCase uc_user.UserDeleteByIDUseCase,
	listFilesByOwnerIDService svc_file.ListFilesByOwnerIDService,
	softDeleteFileService svc_file.SoftDeleteFileService,
	listCollectionsByUserUseCase uc_collection.ListCollectionsByUserUseCase,
	softDeleteCollectionService svc_collection.SoftDeleteCollectionService,
	removeUserFromAllCollectionsUseCase uc_collection.RemoveUserFromAllCollectionsUseCase,
	deleteStorageDailyUsageUseCase uc_storagedailyusage.DeleteByUserUseCase,
	deleteStorageUsageEventUseCase uc_storageusageevent.DeleteByUserUseCase,
	anonymizeUserIPsImmediatelyUseCase uc_user.AnonymizeUserIPsImmediatelyUseCase,
	clearUserCacheUseCase uc_user.ClearUserCacheUseCase,
	anonymizeFileUserReferencesUseCase uc_filemetadata.AnonymizeUserReferencesUseCase,
	anonymizeCollectionUserReferencesUseCase uc_collection.AnonymizeUserReferencesUseCase,
) CompleteUserDeletionService {
	logger = logger.Named("CompleteUserDeletionService")
	return &completeUserDeletionServiceImpl{
		config:                                   config,
		logger:                                   logger,
		getUserUseCase:                           getUserUseCase,
		deleteUserByIDUseCase:                    deleteUserByIDUseCase,
		listFilesByOwnerIDService:                listFilesByOwnerIDService,
		softDeleteFileService:                    softDeleteFileService,
		listCollectionsByUserUseCase:             listCollectionsByUserUseCase,
		softDeleteCollectionService:              softDeleteCollectionService,
		removeUserFromAllCollectionsUseCase:      removeUserFromAllCollectionsUseCase,
		deleteStorageDailyUsageUseCase:           deleteStorageDailyUsageUseCase,
		deleteStorageUsageEventUseCase:           deleteStorageUsageEventUseCase,
		anonymizeUserIPsImmediatelyUseCase:       anonymizeUserIPsImmediatelyUseCase,
		clearUserCacheUseCase:                    clearUserCacheUseCase,
		anonymizeFileUserReferencesUseCase:       anonymizeFileUserReferencesUseCase,
		anonymizeCollectionUserReferencesUseCase: anonymizeCollectionUserReferencesUseCase,
	}
}

func (svc *completeUserDeletionServiceImpl) Execute(ctx context.Context, req *CompleteUserDeletionRequest) (*DeletionResult, error) {
	//
	// STEP 0: Validation
	//
	if req == nil {
		svc.logger.Warn("Failed validation with nil request")
		return nil, httperror.NewForBadRequestWithSingleField("non_field_error", "Request is required")
	}

	e := make(map[string]string)
	if req.UserID.String() == "" {
		e["user_id"] = "User ID is required"
	}
	if len(e) != 0 {
		svc.logger.Warn("Failed validating complete user deletion",
			zap.Any("error", e))
		return nil, httperror.NewForBadRequest(&e)
	}

	result := &DeletionResult{
		UserID:    req.UserID,
		DeletedAt: time.Now(),
		Errors:    []string{},
	}

	svc.logger.Info("🚨 Starting GDPR right-to-be-forgotten complete user deletion",
		zap.String("user_id", req.UserID.String()))

	//
	// STEP 1: Verify user exists
	//
	user, err := svc.getUserUseCase.Execute(ctx, req.UserID)
	if err != nil {
		svc.logger.Error("User not found for deletion",
			zap.String("user_id", req.UserID.String()),
			zap.Error(err))
		return nil, err
	}

	svc.logger.Info("User verified for deletion",
		zap.String("user_id", req.UserID.String()),
		zap.String("email", user.Email))

	//
	// STEP 2: List and hard delete all user files
	//
	svc.logger.Info("Step 2/11: Deleting user files...")

	listFilesReq := &svc_file.ListFilesByOwnerIDRequestDTO{OwnerID: req.UserID}
	filesResp, err := svc.listFilesByOwnerIDService.Execute(ctx, listFilesReq)
	if err != nil {
		svc.logger.Error("Failed to list user files",
			zap.String("user_id", req.UserID.String()),
			zap.Error(err))
		result.Errors = append(result.Errors, fmt.Sprintf("List files: %v", err))
	} else {
		result.FilesDeleted = len(filesResp.Files)
		svc.logger.Info("Found files to delete",
			zap.Int("file_count", result.FilesDeleted))

		// Hard delete each file (no tombstone - GDPR mode)
		for _, file := range filesResp.Files {
			deleteFileReq := &svc_file.SoftDeleteFileRequestDTO{
				FileID:          file.ID,
				ForceHardDelete: true, // GDPR mode - immediate permanent deletion
			}
			deleteResp, err := svc.softDeleteFileService.Execute(ctx, deleteFileReq)
			if err != nil {
				svc.logger.Error("Failed to delete file",
					zap.String("file_id", file.ID.String()),
					zap.Error(err))
				result.Errors = append(result.Errors, fmt.Sprintf("File %s: %v", file.ID, err))
			} else {
				result.S3ObjectsDeleted++
				result.TotalDataSizeBytes += deleteResp.ReleasedBytes
			}
		}
	}

	//
	// STEP 3: List and hard delete all user collections
	//
	svc.logger.Info("Step 3/11: Deleting user collections...")

	collections, err := svc.listCollectionsByUserUseCase.Execute(ctx, req.UserID)
	if err != nil {
		svc.logger.Error("Failed to list user collections",
			zap.String("user_id", req.UserID.String()),
			zap.Error(err))
		result.Errors = append(result.Errors, fmt.Sprintf("List collections: %v", err))
	} else {
		result.CollectionsDeleted = len(collections)
		svc.logger.Info("Found collections to delete",
			zap.Int("collection_count", result.CollectionsDeleted))

		// Hard delete each collection (no tombstone - GDPR mode)
		for _, collection := range collections {
			deleteColReq := &svc_collection.SoftDeleteCollectionRequestDTO{
				ID:              collection.ID,
				ForceHardDelete: true, // GDPR mode - immediate permanent deletion
			}
			_, err := svc.softDeleteCollectionService.Execute(ctx, deleteColReq)
			if err != nil {
				svc.logger.Error("Failed to delete collection",
					zap.String("collection_id", collection.ID.String()),
					zap.Error(err))
				result.Errors = append(result.Errors, fmt.Sprintf("Collection %s: %v", collection.ID, err))
			}
		}
	}

	//
	// STEP 4: Remove user from shared collections
	//
	svc.logger.Info("Step 4/11: Removing user from shared collections...")

	removedCount, err := svc.removeUserFromAllCollectionsUseCase.Execute(ctx, req.UserID, user.Email)
	if err != nil {
		svc.logger.Error("Failed to remove user from shared collections",
			zap.String("user_id", req.UserID.String()),
			zap.Error(err))
		result.Errors = append(result.Errors, fmt.Sprintf("Membership cleanup: %v", err))
	} else {
		result.MembershipsRemoved = removedCount
		svc.logger.Info("Removed user from shared collections",
			zap.Int("memberships_removed", removedCount))
	}

	//
	// STEP 5: Delete storage daily usage data
	//
	svc.logger.Info("Step 5/11: Deleting storage daily usage data...")

	err = svc.deleteStorageDailyUsageUseCase.Execute(ctx, req.UserID)
	if err != nil {
		svc.logger.Error("Failed to delete storage daily usage",
			zap.String("user_id", req.UserID.String()),
			zap.Error(err))
		result.Errors = append(result.Errors, fmt.Sprintf("Storage daily usage: %v", err))
	}

	//
	// STEP 6: Delete storage usage events
	//
	svc.logger.Info("Step 6/11: Deleting storage usage events...")

	err = svc.deleteStorageUsageEventUseCase.Execute(ctx, req.UserID)
	if err != nil {
		svc.logger.Error("Failed to delete storage usage events",
			zap.String("user_id", req.UserID.String()),
			zap.Error(err))
		result.Errors = append(result.Errors, fmt.Sprintf("Storage usage events: %v", err))
	}

	//
	// STEP 7: Anonymize all IP addresses
	//
	svc.logger.Info("Step 7/11: Anonymizing IP addresses...")

	err = svc.anonymizeUserIPsImmediatelyUseCase.Execute(ctx, req.UserID)
	if err != nil {
		svc.logger.Error("Failed to anonymize IP addresses",
			zap.String("user_id", req.UserID.String()),
			zap.Error(err))
		result.Errors = append(result.Errors, fmt.Sprintf("IP anonymization: %v", err))
	}

	//
	// STEP 8: Anonymize user references in files (CreatedByUserID/ModifiedByUserID)
	//
	svc.logger.Info("Step 8/11: Anonymizing user references in files...")

	filesUpdated, err := svc.anonymizeFileUserReferencesUseCase.Execute(ctx, req.UserID)
	if err != nil {
		svc.logger.Error("Failed to anonymize user references in files",
			zap.String("user_id", req.UserID.String()),
			zap.Error(err))
		result.Errors = append(result.Errors, fmt.Sprintf("File user references: %v", err))
	} else {
		svc.logger.Info("Anonymized user references in files",
			zap.Int("files_updated", filesUpdated))
	}

	//
	// STEP 9: Anonymize user references in collections (CreatedByUserID/ModifiedByUserID/GrantedByID)
	//
	svc.logger.Info("Step 9/11: Anonymizing user references in collections...")

	collectionsUpdated, err := svc.anonymizeCollectionUserReferencesUseCase.Execute(ctx, req.UserID)
	if err != nil {
		svc.logger.Error("Failed to anonymize user references in collections",
			zap.String("user_id", req.UserID.String()),
			zap.Error(err))
		result.Errors = append(result.Errors, fmt.Sprintf("Collection user references: %v", err))
	} else {
		svc.logger.Info("Anonymized user references in collections",
			zap.Int("collections_updated", collectionsUpdated))
	}

	//
	// STEP 10: Clear cache and session data
	//
	svc.logger.Info("Step 10/11: Clearing cache and session data...")

	err = svc.clearUserCacheUseCase.Execute(ctx, req.UserID, user.Email)
	if err != nil {
		svc.logger.Error("Failed to clear user cache",
			zap.String("user_id", req.UserID.String()),
			zap.Error(err))
		result.Errors = append(result.Errors, fmt.Sprintf("Cache cleanup: %v", err))
	}

	//
	// STEP 11: Delete user account (final step - point of no return)
	//
	svc.logger.Info("Step 11/11: Deleting user account (final step)...")

	err = svc.deleteUserByIDUseCase.Execute(ctx, req.UserID)
	if err != nil {
		svc.logger.Error("CRITICAL: User account deletion failed",
			zap.String("user_id", req.UserID.String()),
			zap.Error(err))
		return nil, fmt.Errorf("CRITICAL: User account deletion failed: %w", err)
	}

	//
	// SUCCESS
	//
	result.Success = true

	svc.logger.Info("✅ GDPR right-to-be-forgotten complete user deletion SUCCEEDED",
		zap.String("user_id", req.UserID.String()),
		zap.String("email", user.Email),
		zap.Int("files_deleted", result.FilesDeleted),
		zap.Int("collections_deleted", result.CollectionsDeleted),
		zap.Int("s3_objects_deleted", result.S3ObjectsDeleted),
		zap.Int("memberships_removed", result.MembershipsRemoved),
		zap.Int64("data_size_bytes", result.TotalDataSizeBytes),
		zap.Int("non_fatal_errors", len(result.Errors)))

	if len(result.Errors) > 0 {
		svc.logger.Warn("Deletion completed with non-fatal errors",
			zap.Strings("errors", result.Errors))
	}

	return result, nil
}
