package models

import (
	"errors"
	"fmt"
	"time"

	"github.com/sujit-baniya/fiber-boilerplate/app"
	"gorm.io/gorm"
)

type Users struct {
	ID            uint `gorm:"primarykey"`
	CreatedAt     time.Time
	UpdatedAt     time.Time
	DeletedAt     gorm.DeletedAt `gorm:"index"`
	Name          string         `json:"name" gorm:"name"`
	Email         string         `json:"email" gorm:"email"`
	Password      string         `json:"password,omitempty" gorm:"password"`
	EmailVerified bool           `json:"email_verified" gorm:"email_verified"`
	IsAdmin       bool           `json:"is_admin" gorm:"is_admin"`
	RoleID        uint           `json:"role_id" gorm:"role_id"`
	Role          Roles          `gorm:"foreignKey:RoleID"` // Establecer relación con Roles

	NombreUsuario    string `json:"nombre_usuario" gorm:"nombre_usuario"`
	Documento        string `json:"documento" gorm:"documento"`
	Estado           *bool  `json:"estado" gorm:"estado"`
	TipoUsuario      string `json:"tipo" gorm:"tipo_usuario"`
	CogidoUsuarioGas string `json:"cogido_usuario_gas" gorm:"cogido_usuario_gas"`
	NumeroMedidor    string `json:"numero_medidor" gorm:"numero_medidor"`
	TelefonoFijo     string `json:"telefono_fijo" gorm:"telefono_fijo"`
	Celular          string `json:"celular" gorm:"celular"`
	TelegramChatID   string `json:"telegram_chat_id" gorm:"column:telegram_chat_id"`
	AceptoInfo       bool   `json:"acepto_info" gorm:"acepto_info"`
}

// TableName overrides the table name used by Modules to `modules`
func (Users) TableName() string {
	return "users"
}

// AllModules recupera todos los módulos con búsqueda
func AllUsersGas(limit, offset int, search string) ([]Users, int64, error) {
	var users []Users
	var total int64
	db := app.Http.Database.DB.Model(&Users{})

	// Filtrar por término de búsqueda si se proporciona
	if search != "" {
		db = db.Where("name LIKE ? OR nombre_usuario LIKE ?", "%"+search+"%", "%"+search+"%")
	}
	// Filtrar por tipo_usuario = 'gas'
	db = db.Where("tipo_usuario = ?", "gas")

	// Obtener el total de usuarios
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// Obtener los usuarios con paginación y precargar los roles
	if err := db.Order("id DESC").Limit(limit).Offset(offset).
		Preload("Role"). // Precargar la relación Role
		Find(&users).Error; err != nil {
		return nil, 0, err
	}

	return users, total, nil
}

func AllUsersSistema(limit, offset int, search string) ([]Users, int64, error) {
	var users []Users
	var total int64
	db := app.Http.Database.DB.Model(&Users{})

	// Filtrar por término de búsqueda si se proporciona
	if search != "" {
		db = db.Where("name LIKE ? OR nombre_usuario LIKE ?", "%"+search+"%", "%"+search+"%")
	}

	// Filtrar por tipo_usuario = 'sistema' o vacío (excluye usuarios 'gas' y otros tipos)
	db = db.Where("tipo_usuario = ? OR tipo_usuario = '' OR tipo_usuario IS NULL", "sistema")

	// Obtener el total de usuarios
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// Obtener los usuarios con paginación y precargar los roles
	if err := db.Order("id DESC").Limit(limit).Offset(offset).
		Preload("Role"). // Precargar la relación Role
		Find(&users).Error; err != nil {
		return nil, 0, err
	}

	return users, total, nil
}

// CreateModule creates a new module
func CreateUser(User Users) error {
	if err := app.Http.Database.DB.Create(&User).Error; err != nil {
		return err
	}
	return nil
}

// UpdateUser updates an existing user
func UpdateUser(userID uint, Name string, NombreUsuario string, Email string, RoleID int, TelegramChatID string) error {
	updates := map[string]interface{}{
		"name":             Name,
		"nombre_usuario":   NombreUsuario,
		"email":            Email,
		"role_id":          RoleID,
		"telegram_chat_id": TelegramChatID,
	}

	if err := app.Http.Database.DB.Model(&Users{}).Where("id = ?", userID).Updates(updates).Error; err != nil {
		return err
	}
	return nil
}

// UpdateUser updates an existing user
func UpdateUserGas(userID uint, Name string, NombreUsuario string, Email string, Celular string) error {
	// Crea un mapa con los campos a actualizar
	updates := map[string]interface{}{
		"name":           Name,
		"nombre_usuario": NombreUsuario,
		"email":          Email,
		"celular":        Celular,
	}

	// Realiza la actualización de los campos en la base de datos
	if err := app.Http.Database.DB.Model(&Users{}).Where("id = ?", userID).Updates(updates).Error; err != nil {
		return err
	}
	return nil
}

// UpdateUserPassword actualiza solo la contraseña de un usuario existente
func UpdateUserPassword(userID uint, newPassword string) error {
	// Utiliza `Model` para especificar el modelo de Users y `Where` para buscar el usuario
	if err := app.Http.Database.DB.Model(&Users{}).Where("id = ?", userID).Update("password", newPassword).Error; err != nil {
		return err
	}
	return nil
}

// UpdateUser updates an existing user
func UpdateUserEstado(userID uint, Estado bool) error {
	// Crea un mapa con los campos a actualizar
	updates := map[string]interface{}{
		"estado": Estado,
	}

	// Realiza la actualización de los campos en la base de datos
	if err := app.Http.Database.DB.Model(&Users{}).Where("id = ?", userID).Updates(updates).Error; err != nil {
		return err
	}
	return nil
}

// DeleteModule deletes a module by its ID
func DeleteUser(id uint) error {
	if err := app.Http.Database.DB.Delete(&Users{}, id).Error; err != nil {
		return err
	}
	return nil
}

// FindUserByID recupera un solo usuario por su ID
func FindUserByID(id interface{}) (*Users, error) {
	var user Users

	// Asumimos que 'db' está correctamente inicializado en otro lugar de tu aplicación
	db := app.Http.Database.DB.Model(&Users{})

	// Buscar el usuario por ID
	if err := db.Where("id = ?", id).Preload("Role.Submodules.Module").Preload("Role.ConxDBs").First(&user).Error; err != nil {
		// Manejar el error si el registro no se encuentra
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("usuario no encontrado con ID: %d", id)
		}
		return nil, fmt.Errorf("error al buscar usuario: %v", err)
	}

	return &user, nil
}

func GetUserByUsuario(usuario string) (*Users, error) {
	var user Users
	fmt.Println(usuario) // Verifica el usuario recibido
	db := app.Http.Database.DB.Model(&Users{})
	if err := db.Where("nombre_usuario = ? AND email_verified = ? AND estado = ?", usuario, true, true).Preload("Role").First(&user).Error; err != nil {
		return nil, err
	}

	fmt.Println(user) // Verifica el resultado
	return &user, nil
}

func GetUserByUsuarioVerify(usuario string) (*Users, error) {
	var user Users
	if err := app.Http.Database.Where(&Users{NombreUsuario: usuario}).First(&user).Error; err != nil {
		return nil, err
	}
	fmt.Println(user)
	return &user, nil //nolint:wsl
}
func CheckUsernameExists(username string) (bool, error) {
	var user Users
	// Busca un registro en la base de datos
	err := app.Http.Database.Where("nombre_usuario = ?", username).First(&user).Error

	// Si no se encontró el registro, no es un error real
	if err == gorm.ErrRecordNotFound {
		return false, nil
	}

	// Retorna verdadero si no hubo error y falso si ocurrió un error
	if err != nil {
		return false, err
	}

	// Si no hubo error, significa que el usuario existe
	return true, nil
}
