package controllers

import (
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"

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

// ─── Admin: vista principal ───────────────────────────────────────────────────

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

// ─── Recursos ─────────────────────────────────────────────────────────────────

func LoadPartnerRecursos(c *fiber.Ctx) error {
	recursos, err := models.GetAllPartnerRecursos(false)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"recursos": recursos})
}

func CreatePartnerRecurso(c *fiber.Ctx) error {
	type Req struct {
		Nombre      string `json:"nombre"`
		Descripcion string `json:"descripcion"`
		Categoria   string `json:"categoria"`
		Enlace      string `json:"enlace"`
		Activo      bool   `json:"activo"`
	}
	var req Req
	if err := c.BodyParser(&req); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "Datos inválidos"})
	}
	r := &models.PartnerRecurso{
		Nombre:      req.Nombre,
		Descripcion: req.Descripcion,
		Categoria:   req.Categoria,
		Enlace:      req.Enlace,
		Activo:      req.Activo,
	}
	if err := models.CreatePartnerRecurso(r); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.Status(201).JSON(r)
}

func UpdatePartnerRecurso(c *fiber.Ctx) error {
	id, _ := strconv.ParseUint(c.Params("id"), 10, 32)
	type Req struct {
		Nombre      string `json:"nombre"`
		Descripcion string `json:"descripcion"`
		Categoria   string `json:"categoria"`
		Enlace      string `json:"enlace"`
		Activo      bool   `json:"activo"`
	}
	var req Req
	if err := c.BodyParser(&req); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "Datos inválidos"})
	}
	r, err := models.GetPartnerRecursoByID(uint(id))
	if err != nil {
		return c.Status(404).JSON(fiber.Map{"error": "No encontrado"})
	}
	r.Nombre = req.Nombre
	r.Descripcion = req.Descripcion
	r.Categoria = req.Categoria
	r.Enlace = req.Enlace
	r.Activo = req.Activo
	if err := models.UpdatePartnerRecurso(r); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(r)
}

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

func UploadPartnerRecursoArchivo(c *fiber.Ctx) error {
	id, _ := strconv.ParseUint(c.Params("id"), 10, 32)
	file, err := c.FormFile("archivo")
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "Archivo requerido"})
	}
	if file.Size > 50*1024*1024 {
		return c.Status(400).JSON(fiber.Map{"error": "Máximo 50MB"})
	}
	dir := "uploads/partner_recursos"
	if err := os.MkdirAll(dir, 0755); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": "Error al crear directorio"})
	}
	safeFile := safeFilenameProyecto(file.Filename)
	savePath := filepath.Join(dir, fmt.Sprintf("%d_%s", id, safeFile))
	// Validar que la ruta quede dentro de uploads/
	clean := filepath.Clean(savePath)
	if !strings.HasPrefix(clean, "uploads/") {
		return c.Status(400).JSON(fiber.Map{"error": "Ruta inválida"})
	}
	if err := c.SaveFile(file, savePath); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": "Error al guardar archivo"})
	}
	r, err := models.GetPartnerRecursoByID(uint(id))
	if err != nil {
		return c.Status(404).JSON(fiber.Map{"error": "Recurso no encontrado"})
	}
	r.Archivo = savePath
	r.NombreOrig = file.Filename
	if err := models.UpdatePartnerRecurso(r); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"ok": true, "archivo": savePath, "nombre_orig": file.Filename})
}

func DownloadPartnerRecurso(c *fiber.Ctx) error {
	id, _ := strconv.ParseUint(c.Params("id"), 10, 32)
	r, err := models.GetPartnerRecursoByID(uint(id))
	if err != nil || r.Archivo == "" {
		return c.Status(404).JSON(fiber.Map{"error": "Archivo no encontrado"})
	}
	clean := filepath.Clean(r.Archivo)
	if !strings.HasPrefix(clean, "uploads/") {
		return c.Status(403).JSON(fiber.Map{"error": "Acceso denegado"})
	}
	nombre := r.NombreOrig
	if nombre == "" {
		nombre = filepath.Base(r.Archivo)
	}
	c.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, nombre))
	return c.SendFile(clean)
}

// ─── Comunicados ──────────────────────────────────────────────────────────────

func LoadPartnerComunicados(c *fiber.Ctx) error {
	items, err := models.GetAllPartnerComunicados(false)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"comunicados": items})
}

func CreatePartnerComunicado(c *fiber.Ctx) error {
	type Req struct {
		Titulo    string `json:"titulo"`
		Contenido string `json:"contenido"`
		Activo    bool   `json:"activo"`
	}
	var req Req
	if err := c.BodyParser(&req); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "Datos inválidos"})
	}
	item := &models.PartnerComunicado{
		Titulo:    req.Titulo,
		Contenido: req.Contenido,
		Activo:    req.Activo,
	}
	if err := models.CreatePartnerComunicado(item); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.Status(201).JSON(item)
}

func UpdatePartnerComunicado(c *fiber.Ctx) error {
	id, _ := strconv.ParseUint(c.Params("id"), 10, 32)
	type Req struct {
		Titulo    string `json:"titulo"`
		Contenido string `json:"contenido"`
		Activo    bool   `json:"activo"`
	}
	var req Req
	if err := c.BodyParser(&req); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "Datos inválidos"})
	}
	item, err := models.GetPartnerComunicadoByID(uint(id))
	if err != nil {
		return c.Status(404).JSON(fiber.Map{"error": "No encontrado"})
	}
	item.Titulo = req.Titulo
	item.Contenido = req.Contenido
	item.Activo = req.Activo
	if err := models.UpdatePartnerComunicado(item); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(item)
}

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

func UploadPartnerComunicadoArchivo(c *fiber.Ctx) error {
	id, _ := strconv.ParseUint(c.Params("id"), 10, 32)
	file, err := c.FormFile("archivo")
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "Archivo requerido"})
	}
	if file.Size > 50*1024*1024 {
		return c.Status(400).JSON(fiber.Map{"error": "Máximo 50MB"})
	}
	dir := "uploads/partner_comunicados"
	if err := os.MkdirAll(dir, 0755); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": "Error al crear directorio"})
	}
	safeFile := safeFilenameProyecto(file.Filename)
	savePath := filepath.Join(dir, fmt.Sprintf("%d_%s", id, safeFile))
	clean := filepath.Clean(savePath)
	if !strings.HasPrefix(clean, "uploads/") {
		return c.Status(400).JSON(fiber.Map{"error": "Ruta inválida"})
	}
	if err := c.SaveFile(file, savePath); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": "Error al guardar archivo"})
	}
	item, err := models.GetPartnerComunicadoByID(uint(id))
	if err != nil {
		return c.Status(404).JSON(fiber.Map{"error": "Comunicado no encontrado"})
	}
	item.Archivo = savePath
	item.NombreOrig = file.Filename
	if err := models.UpdatePartnerComunicado(item); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"ok": true, "archivo": savePath, "nombre_orig": file.Filename})
}

func DownloadPartnerComunicadoArchivo(c *fiber.Ctx) error {
	id, _ := strconv.ParseUint(c.Params("id"), 10, 32)
	item, err := models.GetPartnerComunicadoByID(uint(id))
	if err != nil || item.Archivo == "" {
		return c.Status(404).JSON(fiber.Map{"error": "Archivo no encontrado"})
	}
	clean := filepath.Clean(item.Archivo)
	if !strings.HasPrefix(clean, "uploads/") {
		return c.Status(403).JSON(fiber.Map{"error": "Acceso denegado"})
	}
	nombre := item.NombreOrig
	if nombre == "" {
		nombre = filepath.Base(item.Archivo)
	}
	c.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, nombre))
	return c.SendFile(clean)
}

// ─── Portal: acceso para partners ────────────────────────────────────────────

func PortalPartnerRecursos(c *fiber.Ctx) error {
	recursos, _ := models.GetAllPartnerRecursos(true)
	comunicados, _ := models.GetAllPartnerComunicados(true)
	return c.JSON(fiber.Map{
		"recursos":    recursos,
		"comunicados": comunicados,
	})
}

func PortalDownloadPartnerRecurso(c *fiber.Ctx) error {
	id, _ := strconv.ParseUint(c.Params("id"), 10, 32)
	r, err := models.GetPartnerRecursoByID(uint(id))
	if err != nil || r.Archivo == "" || !r.Activo {
		return c.Status(404).JSON(fiber.Map{"error": "Archivo no encontrado"})
	}
	clean := filepath.Clean(r.Archivo)
	if !strings.HasPrefix(clean, "uploads/") {
		return c.Status(403).JSON(fiber.Map{"error": "Acceso denegado"})
	}
	nombre := r.NombreOrig
	if nombre == "" {
		nombre = filepath.Base(r.Archivo)
	}
	c.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, nombre))
	return c.SendFile(clean)
}
