// codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/service/me/delete.go
package me

import (
	"context"
	"errors"

	"go.uber.org/zap"

	"github.com/gocql/gocql"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config/constants"
	dom_user "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/user"
	svc_user "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/service/user"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
	sstring "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/security/securestring"
)

type DeleteMeRequestDTO struct {
	Password string `json:"password"`
}

type DeleteMeService interface {
	Execute(sessCtx context.Context, req *DeleteMeRequestDTO) error
}

type deleteMeServiceImpl struct {
	config                      *config.Configuration
	logger                      *zap.Logger
	completeUserDeletionService svc_user.CompleteUserDeletionService
}

func NewDeleteMeService(
	config *config.Configuration,
	logger *zap.Logger,
	completeUserDeletionService svc_user.CompleteUserDeletionService,
) DeleteMeService {
	logger = logger.Named("DeleteMeService")

	return &deleteMeServiceImpl{
		config:                      config,
		logger:                      logger,
		completeUserDeletionService: completeUserDeletionService,
	}
}

func (svc *deleteMeServiceImpl) Execute(sessCtx context.Context, req *DeleteMeRequestDTO) error {
	//
	// STEP 1: Validation
	//

	if req == nil {
		svc.logger.Warn("Failed validation with nil request")
		return httperror.NewForBadRequestWithSingleField("non_field_error", "Password is required")
	}

	e := make(map[string]string)
	if req.Password == "" {
		e["password"] = "Password is required"
	}
	if len(e) != 0 {
		svc.logger.Warn("Failed validation",
			zap.Any("error", e))
		return httperror.NewForBadRequest(&e)
	}

	//
	// STEP 2: Get required from context.
	//

	sessionUserID, ok := sessCtx.Value(constants.SessionUserID).(gocql.UUID)
	if !ok {
		svc.logger.Error("Failed getting local user id",
			zap.Any("error", "Not found in context: user_id"))
		return errors.New("user id not found in context")
	}

	// Defend against admin deleting themselves
	sessionUserRole, _ := sessCtx.Value(constants.SessionUserRole).(int8)
	if sessionUserRole == dom_user.UserRoleRoot {
		svc.logger.Warn("admin is not allowed to delete themselves",
			zap.Any("error", ""))
		return httperror.NewForForbiddenWithSingleField("message", "admins do not have permission to delete themselves")
	}

	//
	// STEP 3: Verify password (intent confirmation).
	//

	securePassword, err := sstring.NewSecureString(req.Password)
	if err != nil {
		svc.logger.Error("Failed to create secure string", zap.Any("error", err))
		return err
	}
	defer securePassword.Wipe()

	// NOTE: In this E2EE architecture, the server does not store password hashes.
	// Password verification happens client-side during key derivation.
	// The frontend must verify the password locally before calling this endpoint
	// by successfully deriving the KEK and decrypting the master key.
	// If the password is wrong, the client-side decryption will fail.
	//
	// The password field in the request serves as a confirmation that the user
	// intentionally wants to delete their account (not cryptographic verification).
	_ = securePassword // Password used for user intent confirmation

	//
	// STEP 4: Execute GDPR right-to-be-forgotten complete deletion
	//

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

	deletionReq := &svc_user.CompleteUserDeletionRequest{
		UserID:   sessionUserID,
		Password: req.Password,
	}

	result, err := svc.completeUserDeletionService.Execute(sessCtx, deletionReq)
	if err != nil {
		svc.logger.Error("Failed to complete user deletion",
			zap.Error(err),
			zap.String("user_id", sessionUserID.String()))
		return err
	}

	//
	// SUCCESS: User account and all data permanently deleted (GDPR compliant)
	//

	svc.logger.Info("User account successfully deleted (GDPR right-to-be-forgotten)",
		zap.String("user_id", sessionUserID.String()),
		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 nil
}
