package handlers

import (
	"net/http"
	"strconv"

	"sale/internal/models"
	"sale/internal/schemas"
	"sale/internal/utils"

	"github.com/gin-gonic/gin"
)

type SystemHandler struct{}

func NewSystemHandler() *SystemHandler {
	return &SystemHandler{}
}

func (h *SystemHandler) GetSettings(c *gin.Context) {
	var settings []models.SystemSetting
	utils.DB.Find(&settings)

	result := make(map[string]string)
	for _, s := range settings {
		result[s.Key] = s.Value
	}

	c.JSON(http.StatusOK, gin.H{"data": result})
}

func (h *SystemHandler) GetPublicSettings(c *gin.Context) {
	publicKeys := []string{
		"payment_channel_fee_rate",
		"shipping_fee_first_weight",
		"shipping_fee_per_gram",
		"service_fee_rate",
		"tax_rate",
		"enabled_payments",
	}
	
	var settings []models.SystemSetting
	utils.DB.Where("`key` IN ?", publicKeys).Find(&settings)

	result := make(map[string]string)
	for _, s := range settings {
		result[s.Key] = s.Value
	}

	c.JSON(http.StatusOK, gin.H{"data": result})
}

func (h *SystemHandler) GetStats(c *gin.Context) {
	var userCount, productCount, orderCount int64
	var totalRevenue float64

	utils.DB.Model(&models.User{}).Count(&userCount)
	utils.DB.Model(&models.Product{}).Count(&productCount)
	utils.DB.Model(&models.Order{}).Count(&orderCount)
	utils.DB.Model(&models.Order{}).Where("status = ?", "completed").Select("COALESCE(SUM(total_amount), 0)").Scan(&totalRevenue)

	c.JSON(http.StatusOK, gin.H{
		"data": gin.H{
			"users":    userCount,
			"products": productCount,
			"orders":   orderCount,
			"revenue":  totalRevenue,
		},
	})
}

func (h *SystemHandler) UpdateSettings(c *gin.Context) {
	var req schemas.UpdateSettingsRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	for key, value := range req.Settings {
		var setting models.SystemSetting
		result := utils.DB.Where("`key` = ?", key).First(&setting)
		if result.Error != nil {
			utils.DB.Create(&models.SystemSetting{Key: key, Value: value})
		} else {
			utils.DB.Model(&setting).Update("value", value)
		}
	}

	c.JSON(http.StatusOK, gin.H{"message": "Settings updated successfully"})
}

func (h *SystemHandler) UpdateSMTP(c *gin.Context) {
	var req map[string]string
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	smtpKeys := []string{"smtp_host", "smtp_port", "smtp_user", "smtp_password", "smtp_from"}
	for _, key := range smtpKeys {
		if value, ok := req[key]; ok {
			var setting models.SystemSetting
			result := utils.DB.Where("`key` = ?", key).First(&setting)
			if result.Error != nil {
				utils.DB.Create(&models.SystemSetting{Key: key, Value: value})
			} else {
				utils.DB.Model(&setting).Update("value", value)
			}
		}
	}

	c.JSON(http.StatusOK, gin.H{"message": "SMTP settings updated successfully"})
}

func (h *SystemHandler) UpdatePayment(c *gin.Context) {
	var req map[string]string
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	for key, value := range req {
		var setting models.SystemSetting
		result := utils.DB.Where("`key` = ?", key).First(&setting)
		if result.Error != nil {
			utils.DB.Create(&models.SystemSetting{Key: key, Value: value})
		} else {
			utils.DB.Model(&setting).Update("value", value)
		}
	}

	c.JSON(http.StatusOK, gin.H{"message": "Payment settings updated successfully"})
}

type SupplierHandler struct{}

func NewSupplierHandler() *SupplierHandler {
	return &SupplierHandler{}
}

func (h *SupplierHandler) List(c *gin.Context) {
	var suppliers []models.User
	utils.DB.Where("role = ?", "supplier").Find(&suppliers)
	c.JSON(http.StatusOK, gin.H{"data": suppliers})
}

func (h *SupplierHandler) Create(c *gin.Context) {
	var req schemas.AddSupplierRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	hashedPassword, _ := utils.HashPassword(req.Password)
	supplier := models.User{
		Username:     req.Username,
		Email:        req.Email,
		PasswordHash: hashedPassword,
		Role:         "supplier",
		InviteCode:   utils.GenerateInviteCode(),
		IsActive:     true,
	}

	utils.DB.Create(&supplier)
	c.JSON(http.StatusCreated, gin.H{"data": supplier})
}

func (h *SupplierHandler) Update(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	var supplier models.User
	if err := utils.DB.Where("id = ? AND role = ?", id, "supplier").First(&supplier).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Supplier not found"})
		return
	}

	var req struct {
		Username *string `json:"username"`
		Email    *string `json:"email"`
		IsActive *bool   `json:"is_active"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	updates := make(map[string]interface{})
	if req.Username != nil {
		updates["username"] = *req.Username
	}
	if req.Email != nil {
		updates["email"] = *req.Email
	}
	if req.IsActive != nil {
		updates["is_active"] = *req.IsActive
	}

	utils.DB.Model(&supplier).Updates(updates)
	utils.DB.Where("id = ?", id).First(&supplier)
	c.JSON(http.StatusOK, gin.H{"data": supplier})
}

func (h *SupplierHandler) Delete(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	utils.DB.Where("id = ? AND role = ?", id, "supplier").Delete(&models.User{})
	c.JSON(http.StatusOK, gin.H{"message": "Supplier deleted successfully"})
}

func (h *SupplierHandler) Authorize(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	var req schemas.AuthorizeSupplierRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	auth := models.SupplierAuthorization{
		SupplierID: uint(id),
		Type:       req.Type,
		RefID:      req.RefID,
	}

	utils.DB.Create(&auth)
	c.JSON(http.StatusCreated, gin.H{"data": auth})
}

type InventoryHandler struct{}

func NewInventoryHandler() *InventoryHandler {
	return &InventoryHandler{}
}

func (h *InventoryHandler) SupplierList(c *gin.Context) {
	userID := c.GetUint("user_id")
	var inventory []models.Inventory
	utils.DB.Where("supplier_id = ?", userID).Preload("Product").Find(&inventory)
	c.JSON(http.StatusOK, gin.H{"data": inventory})
}

func (h *InventoryHandler) Update(c *gin.Context) {
	userID := c.GetUint("user_id")
	id, _ := strconv.Atoi(c.Param("id"))

	var inventory models.Inventory
	if err := utils.DB.Where("id = ? AND supplier_id = ?", id, userID).First(&inventory).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Inventory not found"})
		return
	}

	var req schemas.UpdateInventoryRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	utils.DB.Model(&inventory).Update("quantity", req.Quantity)
	c.JSON(http.StatusOK, gin.H{"data": inventory})
}

func (h *InventoryHandler) AdminList(c *gin.Context) {
	var inventory []models.Inventory
	utils.DB.Preload("Product").Find(&inventory)
	c.JSON(http.StatusOK, gin.H{"data": inventory})
}
