package iam

import (
	"database/sql"
	"time"

	"github.com/atlasos/calypso/internal/common/database"
)

// User represents a system user
type User struct {
	ID           string
	Username     string
	Email        string
	PasswordHash string
	FullName     string
	IsActive     bool
	IsSystem     bool
	CreatedAt    time.Time
	UpdatedAt    time.Time
	LastLoginAt  sql.NullTime
	Roles        []string
	Permissions  []string
}

// GetUserByID retrieves a user by ID
func GetUserByID(db *database.DB, userID string) (*User, error) {
	query := `
		SELECT id, username, email, password_hash, full_name, is_active, is_system,
		       created_at, updated_at, last_login_at
		FROM users
		WHERE id = $1
	`

	var user User
	var lastLogin sql.NullTime
	err := db.QueryRow(query, userID).Scan(
		&user.ID, &user.Username, &user.Email, &user.PasswordHash,
		&user.FullName, &user.IsActive, &user.IsSystem,
		&user.CreatedAt, &user.UpdatedAt, &lastLogin,
	)
	if err != nil {
		return nil, err
	}

	user.LastLoginAt = lastLogin
	return &user, nil
}

// GetUserByUsername retrieves a user by username
func GetUserByUsername(db *database.DB, username string) (*User, error) {
	query := `
		SELECT id, username, email, password_hash, full_name, is_active, is_system,
		       created_at, updated_at, last_login_at
		FROM users
		WHERE username = $1
	`

	var user User
	var lastLogin sql.NullTime
	err := db.QueryRow(query, username).Scan(
		&user.ID, &user.Username, &user.Email, &user.PasswordHash,
		&user.FullName, &user.IsActive, &user.IsSystem,
		&user.CreatedAt, &user.UpdatedAt, &lastLogin,
	)
	if err != nil {
		return nil, err
	}

	user.LastLoginAt = lastLogin
	return &user, nil
}

// GetUserRoles retrieves all roles for a user
func GetUserRoles(db *database.DB, userID string) ([]string, error) {
	query := `
		SELECT r.name
		FROM roles r
		INNER JOIN user_roles ur ON r.id = ur.role_id
		WHERE ur.user_id = $1
	`

	rows, err := db.Query(query, userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var roles []string
	for rows.Next() {
		var role string
		if err := rows.Scan(&role); err != nil {
			return nil, err
		}
		roles = append(roles, role)
	}

	return roles, rows.Err()
}

// GetUserPermissions retrieves all permissions for a user (via roles)
func GetUserPermissions(db *database.DB, userID string) ([]string, error) {
	query := `
		SELECT DISTINCT p.name
		FROM permissions p
		INNER JOIN role_permissions rp ON p.id = rp.permission_id
		INNER JOIN user_roles ur ON rp.role_id = ur.role_id
		WHERE ur.user_id = $1
	`

	rows, err := db.Query(query, userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var permissions []string
	for rows.Next() {
		var perm string
		if err := rows.Scan(&perm); err != nil {
			return nil, err
		}
		permissions = append(permissions, perm)
	}

	return permissions, rows.Err()
}

