// codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/repo/user/update.go
package user

import (
	"context"
	"fmt"
	"time"

	"github.com/gocql/gocql"
	"go.uber.org/zap"

	dom_user "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/user"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/validation"
)

func (impl userStorerImpl) UpdateByID(ctx context.Context, user *dom_user.User) error {
	// First, get the existing user to check what changed
	existingUser, err := impl.GetByID(ctx, user.ID)
	if err != nil {
		return fmt.Errorf("failed to get existing user: %w", err)
	}
	if existingUser == nil {
		return fmt.Errorf("user not found: %s", user.ID)
	}

	// Update modified timestamp
	user.ModifiedAt = time.Now()

	// Serialize data
	profileDataJSON, err := impl.serializeProfileData(user.ProfileData)
	if err != nil {
		return fmt.Errorf("failed to serialize profile data: %w", err)
	}

	securityDataJSON, err := impl.serializeSecurityData(user.SecurityData)
	if err != nil {
		return fmt.Errorf("failed to serialize security data: %w", err)
	}

	metadataJSON, err := impl.serializeMetadata(user.Metadata)
	if err != nil {
		return fmt.Errorf("failed to serialize metadata: %w", err)
	}

	batch := impl.session.NewBatch(gocql.LoggedBatch).WithContext(ctx)

	// 1. Update main table
	batch.Query(`
        UPDATE users_by_id
        SET email = ?, first_name = ?, last_name = ?, name = ?, lexical_name = ?,
            role = ?, status = ?, modified_at = ?,
            profile_data = ?, security_data = ?, metadata = ?
        WHERE id = ?`,
		user.Email, user.FirstName, user.LastName, user.Name, user.LexicalName,
		user.Role, user.Status, user.ModifiedAt,
		profileDataJSON, securityDataJSON, metadataJSON,
		user.ID,
	)

	// 2. Handle email change
	if existingUser.Email != user.Email {
		// Delete old email entry
		batch.Query(`DELETE FROM users_by_email WHERE email = ?`, existingUser.Email)

		// Insert new email entry with ALL fields including security_data
		// IMPORTANT: security_data contains WasEmailVerified flag which must be preserved
		batch.Query(`
            INSERT INTO users_by_email (
                email, id, first_name, last_name, name, lexical_name,
                role, status, timezone, created_at, modified_at,
                profile_data, security_data, metadata
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
			user.Email, user.ID, user.FirstName, user.LastName, user.Name, user.LexicalName,
			user.Role, user.Status, user.Timezone, user.CreatedAt, user.ModifiedAt,
			profileDataJSON, securityDataJSON, metadataJSON,
		)
	} else {
		// Just update the existing email entry
		batch.Query(`
            UPDATE users_by_email
            SET first_name = ?, last_name = ?, name = ?, lexical_name = ?,
                role = ?, status = ?, timezone = ?, modified_at = ?,
                profile_data = ?, security_data = ?, metadata = ?
            WHERE email = ?`,
			user.FirstName, user.LastName, user.Name, user.LexicalName,
			user.Role, user.Status, user.Timezone, user.ModifiedAt,
			profileDataJSON, securityDataJSON, metadataJSON,
			user.Email,
		)
	}

	// 3. Handle status change
	if existingUser.Status != user.Status {
		// Remove from old status table
		// kip

		// Add to new status table
		// Skip

		// Handle active users table
		if existingUser.Status == dom_user.UserStatusActive {
			// Skip
		}
		if user.Status == dom_user.UserStatusActive {
			// Skip
		} else {
			// Just update the existing status entry
			// Skip

			if user.Status == dom_user.UserStatusActive {
				// Skip
			}
		}
	}

	// 4. Handle verification code changes
	// Delete old verification code entry if it exists
	if existingUser.SecurityData != nil && existingUser.SecurityData.Code != "" {
		batch.Query(`DELETE FROM users_by_verification_code WHERE verification_code = ?`, existingUser.SecurityData.Code)
	}

	// Insert new verification code entry if it exists
	if user.SecurityData != nil && user.SecurityData.Code != "" {
		batch.Query(`
            INSERT INTO users_by_verification_code (
                verification_code, id, email, first_name, last_name, name, lexical_name,
                role, status, timezone, created_at, modified_at,
                profile_data, security_data, metadata
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
			user.SecurityData.Code, user.ID, user.Email, user.FirstName, user.LastName, user.Name, user.LexicalName,
			user.Role, user.Status, user.Timezone, user.CreatedAt, user.ModifiedAt,
			profileDataJSON, securityDataJSON, metadataJSON,
		)
	}

	// Execute the batch
	if err := impl.session.ExecuteBatch(batch); err != nil {
		impl.logger.Error("Failed to update user",
			zap.String("user_id", user.ID.String()),
			zap.Error(err))
		return fmt.Errorf("failed to update user: %w", err)
	}

	impl.logger.Info("User updated successfully",
		zap.String("user_id", user.ID.String()),
		zap.String("email", validation.MaskEmail(user.Email)))

	return nil
}
