package controllers

import (
	"os"
	"strconv"

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

// landingSecret verifica que el header X-Landing-Secret sea correcto.
// Si LANDING_API_SECRET no está configurado, se rechaza por seguridad.
func landingSecret(c *fiber.Ctx) bool {
	secret := os.Getenv("LANDING_API_SECRET")
	if secret == "" {
		return false
	}
	return c.Get("X-Landing-Secret") == secret
}

// ─── POST /landing/session ────────────────────────────────────────────────────

// LandingCreateSession crea una nueva sesión de chat para el generador de landing.
func LandingCreateSession(c *fiber.Ctx) error {
	if !landingSecret(c) {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "no autorizado"})
	}

	const firstQuestion = "¡Hola! Soy tu asistente de landing pages. ¿Cuál es tu nombre o el nombre de tu negocio?"

	// Token simple: alfanumérico, 16 chars
	token := helpers.RandomString(16)

	session, err := models.CreateLandingSession(token, firstQuestion)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
	}

	return c.JSON(fiber.Map{"id": session.ID, "token": session.Token})
}

// ─── POST /landing/chat ───────────────────────────────────────────────────────

var landingQuestions = []struct {
	Key      string
	Question string
}{
	{"user_name", "¡Hola! Soy tu asistente de landing pages. ¿Cuál es tu nombre o el nombre de tu negocio?"},
	{"business_type", "¿A qué se dedica tu negocio? Descríbelo brevemente."},
	{"target", "¿A quién va dirigida tu landing page? ¿Cuál es tu cliente ideal?"},
	{"offer", "¿Qué producto o servicio principal quieres destacar?"},
	{"value_prop", "¿Cuál es tu propuesta de valor? ¿Por qué deberían elegirte a ti y no a la competencia?"},
	{"colors", "¿Tienes colores de marca? Descríbelos o dime el estilo visual que prefieres. (Ej: moderno, minimalista, corporativo, colorido)"},
	{"user_phone", "¿Cuál es tu número de teléfono o WhatsApp de contacto?"},
	{"user_email", "¿Cuál es tu correo electrónico de contacto?"},
	{"user_website", "¿Cuál es tu sitio web o portafolio?"},
	{"logo_url", "¿Tienes un logo? Comparte la URL de tu logo (o escribe \"no\" si no tienes)"},
	{"social_media", "¿Qué redes sociales tienes? Comparte tus perfiles de Instagram, LinkedIn, YouTube, TikTok, etc. (Ej: Instagram: @tunombre, LinkedIn: /in/tunombre)"},
	{"user_address", "¿Tienes una dirección física o ciudad donde operas?"},
	{"extras", "¿Hay algo más que quieras incluir? Testimonios, precios, galería, FAQ... (O escribe \"listo\" para generar ya tu landing)"},
}

// LandingChat recibe el mensaje del usuario y devuelve la siguiente pregunta.
func LandingChat(c *fiber.Ctx) error {
	if !landingSecret(c) {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "no autorizado"})
	}

	type body struct {
		Token   string `json:"token"`
		Message string `json:"message"`
	}
	var req body
	if err := c.BodyParser(&req); err != nil || req.Token == "" || req.Message == "" {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "token y message son requeridos"})
	}

	session, err := models.GetLandingSessionByToken(req.Token)
	if err != nil {
		return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "sesión no encontrada"})
	}
	if session.Status != "in_progress" {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "sesión ya finalizada"})
	}

	msgs := session.GetAnswers()
	userAnswersCount := 0
	for _, m := range msgs {
		if m.Role == "user" {
			userAnswersCount++
		}
	}

	msgs = append(msgs, models.LandingMessage{Role: "user", Content: req.Message})

	// Guardar campo estructurado si corresponde
	contactFields := map[string]bool{"user_name": true, "user_phone": true, "user_email": true, "user_website": true, "logo_url": true, "social_media": true, "user_address": true}
	if userAnswersCount < len(landingQuestions) {
		key := landingQuestions[userAnswersCount].Key
		if contactFields[key] {
			switch key {
			case "user_name":
				session.UserName = req.Message
			case "user_phone":
				session.UserPhone = req.Message
			case "user_email":
				session.UserEmail = req.Message
			case "user_website":
				session.UserWebsite = req.Message
			case "logo_url":
				session.LogoUrl = req.Message
			case "social_media":
				session.SocialMedia = req.Message
			case "user_address":
				session.UserAddress = req.Message
			}
		}
	}

	nextIndex := userAnswersCount + 1
	var nextMessage string
	readyToGenerate := false

	if nextIndex < len(landingQuestions) {
		nextMessage = landingQuestions[nextIndex].Question
	} else {
		readyToGenerate = true
		nextMessage = "¡Perfecto! Ya tengo toda la información. ¿Listo para ver tu landing page generada por IA? 🚀"
	}

	msgs = append(msgs, models.LandingMessage{Role: "assistant", Content: nextMessage})
	session.SetAnswers(msgs)

	if err := models.UpdateLandingSession(session); err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
	}

	return c.JSON(fiber.Map{
		"message":         nextMessage,
		"readyToGenerate": readyToGenerate,
		"questionIndex":   nextIndex,
		"totalQuestions":  len(landingQuestions),
	})
}

// ─── GET /landing/preview/:token ─────────────────────────────────────────────

// LandingGetSession devuelve los datos públicos de una sesión (sin HTML si no está pagada).
func LandingGetSession(c *fiber.Ctx) error {
	token := c.Params("token")
	session, err := models.GetLandingSessionByToken(token)
	if err != nil {
		return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "no encontrado"})
	}

	resp := fiber.Map{
		"id":             session.ID,
		"token":          session.Token,
		"status":         session.Status,
		"bold_paid":      session.BoldPaid,
		"price_cop":      session.PriceCOP,
		"user_name":      session.UserName,
		"user_email":     session.UserEmail,
		"user_phone":     session.UserPhone,
		"user_company":   session.UserCompany,
		"user_job":       session.UserJob,
		"user_website":   session.UserWebsite,
		"user_address":   session.UserAddress,
		"social_media":   session.SocialMedia,
		"logo_url":       session.LogoUrl,
		"vcard_included": session.VcardIncluded,
	}
	// Solo exponer el HTML si la sesión está generada (preview con marca de agua siempre)
	if session.HTMLContent != "" {
		resp["html_content"] = session.HTMLContent
	}
	return c.JSON(resp)
}

// LandingGetAnswers devuelve el historial completo de mensajes (requiere secret).
func LandingGetAnswers(c *fiber.Ctx) error {
	if !landingSecret(c) {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "no autorizado"})
	}
	token := c.Params("token")
	session, err := models.GetLandingSessionByToken(token)
	if err != nil {
		return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "no encontrado"})
	}
	return c.JSON(fiber.Map{
		"answers": session.GetAnswers(),
	})
}

// ─── POST /landing/generate ───────────────────────────────────────────────────

// LandingGenerate delega la generación del HTML a un servicio externo (Qwen).
// Recibe el HTML ya generado desde el Next.js y lo persiste.
func LandingGenerate(c *fiber.Ctx) error {
	if !landingSecret(c) {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "no autorizado"})
	}

	type body struct {
		Token         string `json:"token"`
		HTMLContent   string `json:"html_content"`
		VcardIncluded bool   `json:"vcard_included"`
	}
	var req body
	if err := c.BodyParser(&req); err != nil || req.Token == "" || req.HTMLContent == "" {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "token y html_content requeridos"})
	}

	session, err := models.GetLandingSessionByToken(req.Token)
	if err != nil {
		return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "sesión no encontrada"})
	}

	session.HTMLContent = req.HTMLContent
	session.Status = "generated"
	session.VcardIncluded = req.VcardIncluded

	if err := models.UpdateLandingSession(session); err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
	}

	return c.JSON(fiber.Map{"ok": true, "token": session.Token})
}

// ─── POST /landing/payment ────────────────────────────────────────────────────

// LandingCreatePayment genera el link de pago Bold para la sesión.
func LandingCreatePayment(c *fiber.Ctx) error {
	if !landingSecret(c) {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "no autorizado"})
	}

	type body struct {
		Token       string `json:"token"`
		CallbackURL string `json:"callback_url"`
	}
	var req body
	if err := c.BodyParser(&req); err != nil || req.Token == "" {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "token requerido"})
	}

	session, err := models.GetLandingSessionByToken(req.Token)
	if err != nil {
		return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "sesión no encontrada"})
	}

	if session.BoldPaid {
		return c.JSON(fiber.Map{"paid": true, "token": session.Token})
	}

	if session.BoldLinkID != "" {
		boldURL := "https://checkout.bold.co/payment/" + session.BoldLinkID
		return c.JSON(fiber.Map{"url": boldURL, "link_id": session.BoldLinkID})
	}

	cfg, err := models.GetBoldConfig()
	if err != nil {
		return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{"error": "sin configuración Bold activa"})
	}

	reference := "landing-" + session.Token
	callbackURL := req.CallbackURL

	result, err := services.CreateBoldPaymentLink(cfg, services.BoldPaymentLinkRequest{
		AmountType: "CLOSE",
		Amount:     services.BoldAmountField{Currency: "COP", TotalAmount: session.PriceCOP},
		Description: "Landing Page Profesional",
		Reference:   reference,
		PayerEmail:  session.UserEmail,
		CallbackURL: callbackURL,
	})
	if err != nil {
		return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
	}

	session.BoldLinkID = result.Payload.PaymentLink
	_ = models.UpdateLandingSession(session)

	return c.JSON(fiber.Map{"url": result.Payload.URL, "link_id": result.Payload.PaymentLink})
}

// ─── GET /landing/poll/:token ─────────────────────────────────────────────────

// LandingPollPayment verifica el estado del pago (polling desde el cliente).
func LandingPollPayment(c *fiber.Ctx) error {
	token := c.Params("token")

	session, err := models.GetLandingSessionByToken(token)
	if err != nil {
		return c.JSON(fiber.Map{"paid": false})
	}

	if session.BoldPaid {
		return c.JSON(fiber.Map{"paid": true})
	}

	// Consultar la API de Bold si hay un link_id
	if session.BoldLinkID != "" {
		cfg, err := models.GetBoldConfig()
		if err == nil {
			paid, paymentID, _, checkErr := services.CheckBoldLinkPaid(cfg, session.BoldLinkID)
			if checkErr == nil && paid {
				session.BoldPaid = true
				session.BoldPaymentID = paymentID
				session.Status = "paid"
				_ = models.UpdateLandingSession(session)
				return c.JSON(fiber.Map{"paid": true})
			}
		}
	}

	return c.JSON(fiber.Map{"paid": false})
}

// ─── GET /landing/download/:token ────────────────────────────────────────────

// LandingDownload entrega el HTML (o ZIP) solo si la sesión está pagada.
func LandingDownload(c *fiber.Ctx) error {
	if !landingSecret(c) {
		return c.Status(fiber.StatusUnauthorized).SendString("no autorizado")
	}

	token := c.Params("token")
	session, err := models.GetLandingSessionByToken(token)
	if err != nil {
		return c.Status(fiber.StatusNotFound).SendString("no encontrado")
	}
	if !session.BoldPaid {
		return c.Status(fiber.StatusPaymentRequired).SendString("pago requerido")
	}
	if session.HTMLContent == "" {
		return c.Status(fiber.StatusNotFound).SendString("HTML no generado")
	}

	c.Set("Content-Type", "text/html; charset=utf-8")
	c.Set("Content-Disposition", "attachment; filename=\"landing.html\"")
	return c.SendString(session.HTMLContent)
}

// ─── GET /app/landing-pages (admin) ──────────────────────────────────────────

// LandingAdminList lista todas las sesiones para el panel de administración.
func LandingAdminList(c *fiber.Ctx) error {
	page, _ := strconv.Atoi(c.Query("page", "1"))
	perPage := 20
	offset := (page - 1) * perPage
	statusFilter := c.Query("status", "")

	sessions, total, err := models.GetAllLandingSessions(perPage, offset, statusFilter)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
	}

	return c.JSON(fiber.Map{
		"data":  sessions,
		"total": total,
		"page":  page,
	})
}

// ─── GET /landing/ai-config ───────────────────────────────────────────────────

// LandingGetAiConfig devuelve la configuración de IA activa para el Landing Generator.
// Protegido por X-Landing-Secret.
func LandingGetAiConfig(c *fiber.Ctx) error {
	if !landingSecret(c) {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "no autorizado"})
	}
	config, err := models.GetAiConfigForService("landing")
	if err != nil {
		return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "no hay configuración de IA activa"})
	}
	return c.JSON(fiber.Map{
		"provider":   config.Provider,
		"api_key":    config.ApiKey,
		"base_url":   config.BaseURL,
		"model_name": config.ModelName,
	})
}
