package users import ( "fmt" "time" "dk/internal/database" "zombiezen.com/go/sqlite" ) // Builder provides a fluent interface for creating users type Builder struct { user *User db *database.DB } // NewBuilder creates a new user builder with default values func NewBuilder(db *database.DB) *Builder { now := time.Now().Unix() return &Builder{ user: &User{ db: db, Verified: 0, // Default unverified Token: "", // Empty verification token Registered: now, // Current time LastOnline: now, // Current time Auth: 0, // Default no special permissions X: 0, // Default starting position Y: 0, // Default starting position ClassID: 1, // Default to class 1 Currently: "In Town", // Default status Fighting: 0, // Default not fighting HP: 15, // Default starting HP MP: 0, // Default starting MP TP: 10, // Default starting TP MaxHP: 15, // Default starting max HP MaxMP: 0, // Default starting max MP MaxTP: 10, // Default starting max TP Level: 1, // Default starting level Gold: 100, // Default starting gold Exp: 0, // Default starting exp Strength: 5, // Default starting strength Dexterity: 5, // Default starting dexterity Attack: 5, // Default starting attack Defense: 5, // Default starting defense Spells: "", // No spells initially Towns: "", // No towns visited initially }, db: db, } } // WithUsername sets the username func (b *Builder) WithUsername(username string) *Builder { b.user.Username = username return b } // WithPassword sets the password func (b *Builder) WithPassword(password string) *Builder { b.user.Password = password return b } // WithEmail sets the email address func (b *Builder) WithEmail(email string) *Builder { b.user.Email = email return b } // WithVerified sets the verification status func (b *Builder) WithVerified(verified bool) *Builder { if verified { b.user.Verified = 1 } else { b.user.Verified = 0 } return b } // WithToken sets the verification token func (b *Builder) WithToken(token string) *Builder { b.user.Token = token return b } // WithAuth sets the authorization level func (b *Builder) WithAuth(auth int) *Builder { b.user.Auth = auth return b } // AsAdmin sets the user as admin (auth = 4) func (b *Builder) AsAdmin() *Builder { b.user.Auth = 4 return b } // AsModerator sets the user as moderator (auth = 2) func (b *Builder) AsModerator() *Builder { b.user.Auth = 2 return b } // WithClassID sets the character class ID func (b *Builder) WithClassID(classID int) *Builder { b.user.ClassID = classID return b } // WithPosition sets the starting coordinates func (b *Builder) WithPosition(x, y int) *Builder { b.user.X = x b.user.Y = y return b } // WithLevel sets the starting level func (b *Builder) WithLevel(level int) *Builder { b.user.Level = level return b } // WithGold sets the starting gold amount func (b *Builder) WithGold(gold int) *Builder { b.user.Gold = gold return b } // WithStats sets the core character stats func (b *Builder) WithStats(strength, dexterity, attack, defense int) *Builder { b.user.Strength = strength b.user.Dexterity = dexterity b.user.Attack = attack b.user.Defense = defense return b } // WithHP sets current and maximum HP func (b *Builder) WithHP(hp, maxHP int) *Builder { b.user.HP = hp b.user.MaxHP = maxHP return b } // WithMP sets current and maximum MP func (b *Builder) WithMP(mp, maxMP int) *Builder { b.user.MP = mp b.user.MaxMP = maxMP return b } // WithTP sets current and maximum TP func (b *Builder) WithTP(tp, maxTP int) *Builder { b.user.TP = tp b.user.MaxTP = maxTP return b } // WithCurrently sets the current status message func (b *Builder) WithCurrently(currently string) *Builder { b.user.Currently = currently return b } // WithRegistered sets the registration timestamp func (b *Builder) WithRegistered(registered int64) *Builder { b.user.Registered = registered return b } // WithRegisteredTime sets the registration timestamp from time.Time func (b *Builder) WithRegisteredTime(t time.Time) *Builder { b.user.Registered = t.Unix() return b } // WithSpells sets the user's known spells func (b *Builder) WithSpells(spells []string) *Builder { b.user.SetSpellIDs(spells) return b } // WithTowns sets the user's visited towns func (b *Builder) WithTowns(towns []string) *Builder { b.user.SetTownIDs(towns) return b } // Create saves the user to the database and returns the created user with ID func (b *Builder) Create() (*User, error) { // Use a transaction to ensure we can get the ID var user *User err := b.db.Transaction(func(tx *database.Tx) error { query := `INSERT INTO users (username, password, email, verified, token, registered, last_online, auth, x, y, class_id, currently, fighting, monster_id, monster_hp, monster_sleep, monster_immune, uber_damage, uber_defense, hp, mp, tp, max_hp, max_mp, max_tp, level, gold, exp, gold_bonus, exp_bonus, strength, dexterity, attack, defense, weapon_id, armor_id, shield_id, slot_1_id, slot_2_id, slot_3_id, weapon_name, armor_name, shield_name, slot_1_name, slot_2_name, slot_3_name, drop_code, spells, towns) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` if err := tx.Exec(query, b.user.Username, b.user.Password, b.user.Email, b.user.Verified, b.user.Token, b.user.Registered, b.user.LastOnline, b.user.Auth, b.user.X, b.user.Y, b.user.ClassID, b.user.Currently, b.user.Fighting, b.user.MonsterID, b.user.MonsterHP, b.user.MonsterSleep, b.user.MonsterImmune, b.user.UberDamage, b.user.UberDefense, b.user.HP, b.user.MP, b.user.TP, b.user.MaxHP, b.user.MaxMP, b.user.MaxTP, b.user.Level, b.user.Gold, b.user.Exp, b.user.GoldBonus, b.user.ExpBonus, b.user.Strength, b.user.Dexterity, b.user.Attack, b.user.Defense, b.user.WeaponID, b.user.ArmorID, b.user.ShieldID, b.user.Slot1ID, b.user.Slot2ID, b.user.Slot3ID, b.user.WeaponName, b.user.ArmorName, b.user.ShieldName, b.user.Slot1Name, b.user.Slot2Name, b.user.Slot3Name, b.user.DropCode, b.user.Spells, b.user.Towns); err != nil { return fmt.Errorf("failed to insert user: %w", err) } // Get the last insert ID var id int err := tx.Query("SELECT last_insert_rowid()", func(stmt *sqlite.Stmt) error { id = stmt.ColumnInt(0) return nil }) if err != nil { return fmt.Errorf("failed to get insert ID: %w", err) } b.user.ID = id user = b.user return nil }) if err != nil { return nil, err } return user, nil }