package controllers

import (
	"math"
	"strconv"
	"strings"

	"github.com/gofiber/fiber/v2"
	"github.com/sujit-baniya/fiber-boilerplate/app"
	"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
	"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
)

func PortalUsuariosIndex(c *fiber.Ctx) error {
	return c.Render("portal_usuarios", fiber.Map{
		"user":    c.Locals("user"),
		"modules": c.Locals("userModules"),
	}, "layouts/main")
}

func LoadPortalUsuarios(c *fiber.Ctx) error {
	page, _ := strconv.Atoi(c.Query("page", "1"))
	if page < 1 {
		page = 1
	}
	limit := 20
	offset := (page - 1) * limit
	items, total, err := models.GetAllPortalUsers(limit, offset)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	clientes, _, _ := models.GetAllClientes(200, 0, "")
	portalRoles, _ := models.GetPortalRoles()
	return c.JSON(fiber.Map{
		"items":       items,
		"total":       total,
		"totalPages":  int(math.Ceil(float64(total) / float64(limit))),
		"page":        page,
		"clientes":    clientes,
		"portalRoles": portalRoles,
	})
}

func CreatePortalUsuario(c *fiber.Ctx) error {
	type Req struct {
		Nombre         string `json:"nombre"`
		Email          string `json:"email"`
		Password       string `json:"password"`
		ClienteID      *uint  `json:"cliente_id"`
		RoleID         *uint  `json:"role_id"`
		Rol            string `json:"rol"`
		Notas          string `json:"notas"`
		TelegramChatID string `json:"telegram_chat_id"`
		SitioWeb       string `json:"sitio_web"`
		Telefono       string `json:"telefono"`
		Indicativo     string `json:"indicativo"`
		Pais           string `json:"pais"`
		Ciudad         string `json:"ciudad"`
	}
	var req Req
	if err := c.BodyParser(&req); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": err.Error()})
	}
	if strings.TrimSpace(req.Nombre) == "" || strings.TrimSpace(req.Email) == "" || strings.TrimSpace(req.Password) == "" {
		return c.Status(400).JSON(fiber.Map{"error": "nombre, email y password son requeridos"})
	}
	hashed, err := app.Http.Hash.Create(req.Password)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": "Error al hashear contraseña"})
	}
	if req.Rol == "" {
		req.Rol = "cliente"
	}
	// Derivar Rol del tipo de rol seleccionado
	rol := req.Rol
	if req.RoleID != nil {
		var role models.Roles
		if err := app.Http.Database.DB.First(&role, *req.RoleID).Error; err == nil {
			if role.EsPortalPartner {
				rol = "partner"
			}
		}
	}
	u := &models.PortalUser{
		Nombre:         req.Nombre,
		Email:          strings.ToLower(strings.TrimSpace(req.Email)),
		Password:       hashed,
		ClienteID:      req.ClienteID,
		RoleID:         req.RoleID,
		Rol:            rol,
		Activo:         true,
		Notas:          req.Notas,
		TelegramChatID: req.TelegramChatID,
		SitioWeb:       req.SitioWeb,
		Telefono:       req.Telefono,
		Indicativo:     req.Indicativo,
		Pais:           req.Pais,
		Ciudad:         req.Ciudad,
	}
	if err := models.CreatePortalUser(u); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	u.Password = ""
	return c.Status(201).JSON(u)
}

func UpdatePortalUsuario(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
	}
	type Req struct {
		Nombre         string `json:"nombre"`
		Email          string `json:"email"`
		Password       string `json:"password"`
		ClienteID      *uint  `json:"cliente_id"`
		RoleID         *uint  `json:"role_id"`
		Rol            string `json:"rol"`
		Activo         bool   `json:"activo"`
		Notas          string `json:"notas"`
		TelegramChatID string `json:"telegram_chat_id"`
		SitioWeb       string `json:"sitio_web"`
		Telefono       string `json:"telefono"`
		Indicativo     string `json:"indicativo"`
		Pais           string `json:"pais"`
		Ciudad         string `json:"ciudad"`
	}
	var req Req
	if err := c.BodyParser(&req); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": err.Error()})
	}
	// Derivar Rol del tipo de rol seleccionado
	rol := req.Rol
	if req.RoleID != nil {
		var role models.Roles
		if err := app.Http.Database.DB.First(&role, *req.RoleID).Error; err == nil {
			if role.EsPortalPartner {
				rol = "partner"
			}
		}
	}
	u := &models.PortalUser{
		Nombre:         req.Nombre,
		Email:          strings.ToLower(strings.TrimSpace(req.Email)),
		ClienteID:      req.ClienteID,
		RoleID:         req.RoleID,
		Rol:            rol,
		Activo:         req.Activo,
		Notas:          req.Notas,
		TelegramChatID: req.TelegramChatID,
		SitioWeb:       req.SitioWeb,
		Telefono:       req.Telefono,
		Indicativo:     req.Indicativo,
		Pais:           req.Pais,
		Ciudad:         req.Ciudad,
	}
	u.ID = uint(id)
	if err := models.UpdatePortalUser(u); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	// Actualizar password solo si se envió
	if strings.TrimSpace(req.Password) != "" {
		hashed, err := app.Http.Hash.Create(req.Password)
		if err == nil {
			_ = models.UpdatePortalUserPassword(uint(id), hashed)
		}
	}
	return c.JSON(fiber.Map{"ok": true})
}

func DeletePortalUsuario(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
	}
	if err := models.DeletePortalUser(uint(id)); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"ok": true})
}

func AddPortalAcceso(c *fiber.Ctx) error {
	id, _ := strconv.ParseUint(c.Params("id"), 10, 32)
	type Req struct {
		ClienteID uint `json:"cliente_id"`
	}
	var req Req
	if err := c.BodyParser(&req); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": err.Error()})
	}
	if err := models.AddPortalAcceso(uint(id), req.ClienteID); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"ok": true})
}

func RemovePortalAcceso(c *fiber.Ctx) error {
	id, _ := strconv.ParseUint(c.Params("id"), 10, 32)
	clienteID, _ := strconv.ParseUint(c.Params("clienteID"), 10, 32)
	if err := models.RemovePortalAcceso(uint(id), uint(clienteID)); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"ok": true})
}

// SendPortalCredentials envía las credenciales de acceso al portal al correo del usuario.
func SendPortalCredentials(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
	}
	u, err := models.GetPortalUserByID(uint(id))
	if err != nil {
		return c.Status(404).JSON(fiber.Map{"error": "Usuario no encontrado"})
	}

	type Req struct {
		Password string `json:"password"`
	}
	var req Req
	_ = c.BodyParser(&req)

	password := req.Password
	if password == "" {
		password = "(la contraseña que configuraste)"
	}

	services.SendPortalCredentialsEmail(u.Email, u.Nombre, password)
	return c.JSON(fiber.Map{"ok": true, "message": "Correo enviado a " + u.Email})
}

// GetPortalUsuarioDetail devuelve todos los campos de un portal_user para el panel de detalle.
func GetPortalUsuarioDetail(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
	}
	u, err := models.GetPortalUserByID(uint(id))
	if err != nil {
		return c.Status(404).JSON(fiber.Map{"error": "Usuario no encontrado"})
	}
	return c.JSON(u)
}

// PortalUsuarioRutFile sirve el archivo RUT/documento del portal user al admin.
func PortalUsuarioRutFile(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
	}
	u, err := models.GetPortalUserByID(uint(id))
	if err != nil {
		return c.Status(404).JSON(fiber.Map{"error": "Usuario no encontrado"})
	}
	if u.DocumentoRutFile == "" {
		return c.Status(404).JSON(fiber.Map{"error": "Este usuario no tiene archivo RUT"})
	}
	return c.SendFile(u.DocumentoRutFile)
}
