package main

import (
	"context"
	"fmt"
	"time"

	"golang.org/x/crypto/bcrypt"
)

type User struct {
	ID        int64      `json:"id"`
	Username  string     `json:"username"`
	Role      string     `json:"role"`
	Status    string     `json:"status"`
	FullName  string     `json:"full_name"`
	Email     string     `json:"email"`
	LastLogin *time.Time `json:"last_login"`
	CreatedAt time.Time  `json:"created_at"`
	UpdatedAt time.Time  `json:"updated_at"`
}

// seedDefaultUsers is DISABLED - use ic3_user_master table with your actual users
// func (db *DB) seedDefaultUsers(ctx context.Context) {
// 	defaults := []struct{ username, password, role, fullName string }{
// 		{"admin",    "admin123",  "admin",    "System Administrator"},
// 		{"operator", "op123",     "operator", "Operations User"},
// 		{"viewer",   "view123",   "viewer",   "Read-Only Viewer"},
// 	}
// 	for _, d := range defaults {
// 		var exists bool
// 		db.pool.QueryRow(ctx,
// 			`SELECT EXISTS(SELECT 1 FROM ic3_user_master WHERE username=$1)`, d.username,
// 		).Scan(&exists)
// 		if exists {
// 			continue
// 		}
// 		hash, err := bcrypt.GenerateFromPassword([]byte(d.password), bcrypt.DefaultCost)
// 		if err != nil {
// 			log.Printf("seed user %s: %v", d.username, err)
// 			continue
// 		}
// 		db.pool.Exec(ctx,
// 			`INSERT INTO ic3_user_master (username, password_hash, role_id, full_name)
// 			 VALUES ($1,$2,(SELECT role_id FROM ic3_role_master WHERE role_name=$3),$4) ON CONFLICT (username) DO NOTHING`,
// 			d.username, string(hash), d.role, d.fullName,
// 		)
// 		log.Printf("Seeded user: %s (%s)", d.username, d.role)
// 	}
// }

// listUsers returns all users (password hash excluded).
func (db *DB) listUsers(ctx context.Context) ([]User, error) {
	rows, err := db.pool.Query(ctx,
		`SELECT id, username, role, status,
		        COALESCE(full_name,''), COALESCE(email,''), last_login, created_at, updated_at
		 FROM users ORDER BY id ASC`)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var out []User
	for rows.Next() {
		var u User
		if err := rows.Scan(&u.ID, &u.Username, &u.Role, &u.Status,
			&u.FullName, &u.Email, &u.LastLogin, &u.CreatedAt, &u.UpdatedAt); err != nil {
			continue
		}
		out = append(out, u)
	}
	return out, nil
}

// createUser inserts a new user with a bcrypt-hashed password.
func (db *DB) createUser(ctx context.Context, username, password, role, fullName, email string) (*User, error) {
	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return nil, err
	}
	var u User
	err = db.pool.QueryRow(ctx,
		`INSERT INTO users (username, password_hash, role, full_name, email)
		 VALUES ($1,$2,$3,$4,$5)
		 RETURNING id, username, role, status,
		           COALESCE(full_name,''), COALESCE(email,''), last_login, created_at, updated_at`,
		username, string(hash), role, nullText(fullName), nullText(email),
	).Scan(&u.ID, &u.Username, &u.Role, &u.Status,
		&u.FullName, &u.Email, &u.LastLogin, &u.CreatedAt, &u.UpdatedAt)
	if err != nil {
		return nil, err
	}
	return &u, nil
}

// updateUser changes role, status, full_name and email for the given user ID.
func (db *DB) updateUser(ctx context.Context, id int64, role, status, fullName, email string) (*User, error) {
	var u User
	err := db.pool.QueryRow(ctx,
		`UPDATE users
		 SET role=$2, status=$3, full_name=NULLIF($4,''), email=NULLIF($5,''), updated_at=NOW()
		 WHERE id=$1
		 RETURNING id, username, role, status,
		           COALESCE(full_name,''), COALESCE(email,''), last_login, created_at, updated_at`,
		id, role, status, fullName, email,
	).Scan(&u.ID, &u.Username, &u.Role, &u.Status,
		&u.FullName, &u.Email, &u.LastLogin, &u.CreatedAt, &u.UpdatedAt)
	if err != nil {
		return nil, err
	}
	return &u, nil
}

// deleteUser removes a user by ID. Returns error if user not found.
func (db *DB) deleteUser(ctx context.Context, id int64) error {
	ct, err := db.pool.Exec(ctx, `DELETE FROM users WHERE id=$1`, id)
	if err != nil {
		return err
	}
	if ct.RowsAffected() == 0 {
		return fmt.Errorf("user not found")
	}
	return nil
}

// resetPassword sets a new bcrypt-hashed password for the given user ID.
func (db *DB) resetPassword(ctx context.Context, id int64, newPassword string) error {
	hash, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
	if err != nil {
		return err
	}
	ct, err := db.pool.Exec(ctx,
		`UPDATE users SET password_hash=$2, updated_at=NOW() WHERE id=$1`,
		id, string(hash))
	if err != nil {
		return err
	}
	if ct.RowsAffected() == 0 {
		return fmt.Errorf("user not found")
	}
	return nil
}
