package dbstore

import (
	"encoding/json"
	"fmt"

	"git.linuxforward.com/byop/byop-engine/dbmanager"
	"git.linuxforward.com/byop/byop-engine/models"
)

type UserStore struct {
	dbConn dbmanager.DbManager
}

// NewUserStore creates a new UserStore
func NewUserStore(dbConn dbmanager.DbManager) *UserStore {
	return &UserStore{
		dbConn: dbConn,
	}
}

func (us *UserStore) CreateTable() error {
	query := `
    CREATE TABLE IF NOT EXISTS users (
        id TEXT PRIMARY KEY,
        data TEXT NOT NULL
    );`
	_, err := us.dbConn.Exec(query)
	if err != nil {
		return fmt.Errorf("failed to create users table: %w", err)
	}
	return nil
}

// Create creates a new user
func (us *UserStore) Create(user *models.User) error {
	return us.dbConn.Create("users", user)
}

// GetByID retrieves a user by ID
func (us *UserStore) GetByID(id string) (*models.User, error) {
	user, err := us.dbConn.GetByID("users", id)
	if err != nil {
		return nil, err
	}
	return user.(*models.User), nil
}

// Update updates an existing user
func (us *UserStore) Update(user *models.User) error {
	return us.dbConn.Update("users", user)
}

// Delete deletes a user by ID
func (us *UserStore) Delete(id string) error {
	return us.dbConn.Delete("users", id)
}

// List retrieves all users
func (us *UserStore) List(filter map[string]interface{}) ([]*models.User, error) {
	users, err := us.dbConn.List("users", filter)
	if err != nil {
		return nil, err
	}

	// If no users are found, return an empty slice
	if len(users) == 0 {
		return []*models.User{}, nil
	}
	var userList []*models.User
	for _, user := range users {
		userData, ok := user.(map[string]interface{})
		if !ok {
			return nil, fmt.Errorf("unexpected data format")
		}

		// Unmarshal the map into a *models.User
		user := &models.User{}
		jsonData, err := json.Marshal(userData)
		if err != nil {
			return nil, fmt.Errorf("failed to marshal user data: %w", err)
		}

		if err := json.Unmarshal(jsonData, user); err != nil {
			return nil, fmt.Errorf("failed to unmarshal user data: %w", err)
		}
		userList = append(userList, user)
	}
	return userList, nil
}

// GetByUsername retrieves a user by username
func (us *UserStore) GetByUsername(username string) (*models.User, error) {
	user, err := us.dbConn.GetByID("users", username)
	if err != nil {
		return nil, err
	}
	return user.(*models.User), nil
}

func (us *UserStore) GetUserByEmail(email string) (*models.User, error) {
	// Retrieve the list of users filtered by email
	users, err := us.dbConn.List("users", map[string]interface{}{"email": email})
	if err != nil {
		return nil, err
	}

	// If no users are found, return nil
	if len(users) == 0 {
		return nil, nil
	}

	// Convert the first result to *models.User
	userData, ok := users[0].(map[string]interface{})
	if !ok {
		return nil, fmt.Errorf("unexpected data format")
	}

	// Unmarshal the map into a *models.User
	user := &models.User{}
	jsonData, err := json.Marshal(userData)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal user data: %w", err)
	}

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

	return user, nil
}

// ListDeploymentsByUserID retrieves all deployments for a user by user ID
func (us *UserStore) ListDeploymentsByUserID(userID string) ([]*models.Deployment, error) {
	deployments, err := us.dbConn.List("deployments", map[string]interface{}{"user_id": userID})
	if err != nil {
		return nil, err
	}

	var deploymentList []*models.Deployment
	for _, deployment := range deployments {
		deploymentList = append(deploymentList, deployment.(*models.Deployment))
	}
	return deploymentList, nil
}
