package db

import (
	"database/sql"
	"errors"
	"fmt"

	_ "github.com/mattn/go-sqlite3"
)

/**
 * @brief Структура пользователя
 */
type User struct {
	ID             int
	Username       string
	PasswordHash   string
	FailedAttempts int
	Locked         bool
}

var database *sql.DB

/**
 * @brief Инициализация соединения с SQLite БД
 * @param path Путь к файлу базы данных
 * @return ошибка при неудаче
 */
func Init(path string) error {
	var err error

	database, err = sql.Open("sqlite3", path)
	if err != nil {
		return err
	}

	// Проверка соединения
	if err = database.Ping(); err != nil {
		return err
	}

	return createTables()
}

/**
 * @brief Закрытие соединения с БД
 */
func Close() {
	if database != nil {
		_ = database.Close()
	}
}

/**
 * @brief Создание таблиц при первом запуске
 */
func createTables() error {
	query := `
	CREATE TABLE IF NOT EXISTS users (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		username TEXT UNIQUE NOT NULL,
		password_hash TEXT NOT NULL,
		failed_attempts INTEGER DEFAULT 0,
		locked INTEGER DEFAULT 0
	);
	`

	_, err := database.Exec(query)
	return err
}

/**
 * @brief Получить пользователя по имени
 * @param username Логин пользователя
 * @return структура User или ошибка
 */
func GetUser(username string) (*User, error) {
	query := `
	SELECT id, username, password_hash, failed_attempts, locked
	FROM users
	WHERE username = ?;
	`

	row := database.QueryRow(query, username)

	var user User
	var locked int

	err := row.Scan(
		&user.ID,
		&user.Username,
		&user.PasswordHash,
		&user.FailedAttempts,
		&locked,
	)

	if err == sql.ErrNoRows {
		return nil, errors.New("пользователь не найден")
	}
	if err != nil {
		return nil, err
	}

	user.Locked = locked != 0
	return &user, nil
}

/**
 * @brief Увеличить счётчик неудачных попыток входа
 * @param username Логин пользователя
 */
func IncrementFail(username string) error {
	query := `
	UPDATE users
	SET failed_attempts = failed_attempts + 1
	WHERE username = ?;
	`

	_, err := database.Exec(query, username)
	return err
}

/**
 * @brief Сбросить счётчик неудачных попыток
 * @param username Логин пользователя
 */
func ResetFails(username string) error {
	query := `
	UPDATE users
	SET failed_attempts = 0
	WHERE username = ?;
	`

	_, err := database.Exec(query, username)
	return err
}

/**
 * @brief Заблокировать пользователя
 * @param username Логин пользователя
 */
func LockUser(username string) error {
	query := `
	UPDATE users
	SET locked = 1
	WHERE username = ?;
	`

	_, err := database.Exec(query)
	return err
}

/**
 * @brief Добавить нового пользователя (для инициализации)
 * @param username Логин
 * @param passwordHash Хеш пароля
 */
func CreateUser(username, passwordHash string) error {
	query := `
	INSERT INTO users (username, password_hash)
	VALUES (?, ?);
	`

	_, err := database.Exec(query, username, passwordHash)
	if err != nil {
		return fmt.Errorf("не удалось создать пользователя: %w", err)
	}

	return nil
}
