package user

import (
	"encoding/json"
	"fmt"

	"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/pkg/storage"
	"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/domain/user"
)

const (
	userKeyPrefix = "user:"
	emailKeyIndex = "email_index:"
)

type repository struct {
	storage storage.Storage
}

// ProvideRepository creates a new user repository
func ProvideRepository(storage storage.Storage) user.Repository {
	return &repository{
		storage: storage,
	}
}

func (r *repository) Save(u *user.User) error {
	data, err := json.Marshal(u)
	if err != nil {
		return fmt.Errorf("failed to marshal user: %w", err)
	}

	// Save user by ID
	userKey := userKeyPrefix + u.ID
	if err := r.storage.Set(userKey, data); err != nil {
		return fmt.Errorf("failed to save user: %w", err)
	}

	// Create email index
	emailKey := emailKeyIndex + u.Email
	if err := r.storage.Set(emailKey, []byte(u.ID)); err != nil {
		return fmt.Errorf("failed to create email index: %w", err)
	}

	return nil
}

func (r *repository) GetByID(id string) (*user.User, error) {
	key := userKeyPrefix + id
	data, err := r.storage.Get(key)
	if err != nil {
		return nil, fmt.Errorf("failed to get user: %w", err)
	}

	var u user.User
	if err := json.Unmarshal(data, &u); err != nil {
		return nil, fmt.Errorf("failed to unmarshal user: %w", err)
	}

	return &u, nil
}

func (r *repository) GetByEmail(email string) (*user.User, error) {
	// Get user ID from email index
	emailKey := emailKeyIndex + email
	idData, err := r.storage.Get(emailKey)
	if err != nil {
		return nil, fmt.Errorf("user not found by email: %w", err)
	}

	userID := string(idData)
	return r.GetByID(userID)
}

func (r *repository) Delete(id string) error {
	// Get user first to remove email index
	u, err := r.GetByID(id)
	if err != nil {
		return err
	}

	// Delete email index
	emailKey := emailKeyIndex + u.Email
	if err := r.storage.Delete(emailKey); err != nil {
		return fmt.Errorf("failed to delete email index: %w", err)
	}

	// Delete user
	userKey := userKeyPrefix + id
	if err := r.storage.Delete(userKey); err != nil {
		return fmt.Errorf("failed to delete user: %w", err)
	}

	return nil
}

func (r *repository) Exists(id string) (bool, error) {
	key := userKeyPrefix + id
	_, err := r.storage.Get(key)
	if err != nil {
		// Key doesn't exist
		return false, nil
	}
	return true, nil
}
