package controllers

import (
	"net/http"
	"strings"

	"fotbal-club/internal/models"

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

// ContactInfoController handles contact information and categories
type ContactInfoController struct {
	DB *gorm.DB
}

// NewContactInfoController creates a new ContactInfoController
func NewContactInfoController(db *gorm.DB) *ContactInfoController {
	return &ContactInfoController{DB: db}
}

// ==================== PUBLIC ENDPOINTS ====================

// GetPublicContacts returns all active contacts grouped by category (public)
func (ctrl *ContactInfoController) GetPublicContacts(c *gin.Context) {
	var contacts []models.Contact
	if err := ctrl.DB.Preload("Category").
		Where("is_active = ?", true).
		Order("display_order ASC, created_at ASC").
		Find(&contacts).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load contacts"})
		return
	}

	// Group by category
	grouped := make(map[string][]models.Contact)
	uncategorized := []models.Contact{}
	
	for _, contact := range contacts {
		if contact.Category != nil && contact.Category.IsActive {
			grouped[contact.Category.Name] = append(grouped[contact.Category.Name], contact)
		} else {
			uncategorized = append(uncategorized, contact)
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"categories": grouped,
		"uncategorized": uncategorized,
	})
}

// GetPublicContactCategories returns all active contact categories (public)
func (ctrl *ContactInfoController) GetPublicContactCategories(c *gin.Context) {
	var categories []models.ContactCategory
	if err := ctrl.DB.Where("is_active = ?", true).
		Order("display_order ASC, name ASC").
		Find(&categories).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load categories"})
		return
	}

	c.JSON(http.StatusOK, categories)
}

// ==================== ADMIN: CONTACT CATEGORIES ====================

// GetContactCategories lists all contact categories (admin)
func (ctrl *ContactInfoController) GetContactCategories(c *gin.Context) {
	var categories []models.ContactCategory
	if err := ctrl.DB.Order("display_order ASC, name ASC").Find(&categories).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load categories"})
		return
	}

	c.JSON(http.StatusOK, categories)
}

// CreateContactCategory creates a new contact category (admin)
func (ctrl *ContactInfoController) CreateContactCategory(c *gin.Context) {
	var body struct {
		Name         string `json:"name" binding:"required"`
		Description  string `json:"description"`
		DisplayOrder *int   `json:"display_order"`
		IsActive     *bool  `json:"is_active"`
	}
	if err := c.ShouldBindJSON(&body); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	category := models.ContactCategory{
		Name:        strings.TrimSpace(body.Name),
		Description: strings.TrimSpace(body.Description),
	}
	
	if body.DisplayOrder != nil {
		category.DisplayOrder = *body.DisplayOrder
	}
	if body.IsActive != nil {
		category.IsActive = *body.IsActive
	} else {
		category.IsActive = true
	}

	if err := ctrl.DB.Create(&category).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create category"})
		return
	}

	c.JSON(http.StatusCreated, category)
}

// UpdateContactCategory updates a contact category (admin)
func (ctrl *ContactInfoController) UpdateContactCategory(c *gin.Context) {
	id := c.Param("id")
	
	var category models.ContactCategory
	if err := ctrl.DB.First(&category, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			c.JSON(http.StatusNotFound, gin.H{"error": "Category not found"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
		return
	}

	var body struct {
		Name         *string `json:"name"`
		Description  *string `json:"description"`
		DisplayOrder *int    `json:"display_order"`
		IsActive     *bool   `json:"is_active"`
	}
	if err := c.ShouldBindJSON(&body); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if body.Name != nil {
		category.Name = strings.TrimSpace(*body.Name)
	}
	if body.Description != nil {
		category.Description = strings.TrimSpace(*body.Description)
	}
	if body.DisplayOrder != nil {
		category.DisplayOrder = *body.DisplayOrder
	}
	if body.IsActive != nil {
		category.IsActive = *body.IsActive
	}

	if err := ctrl.DB.Save(&category).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update category"})
		return
	}

	c.JSON(http.StatusOK, category)
}

// DeleteContactCategory deletes a contact category (admin)
func (ctrl *ContactInfoController) DeleteContactCategory(c *gin.Context) {
	id := c.Param("id")
	
	// Check if any contacts use this category
	var count int64
	if err := ctrl.DB.Model(&models.Contact{}).Where("category_id = ?", id).Count(&count).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
		return
	}

	if count > 0 {
		c.JSON(http.StatusConflict, gin.H{"error": "Cannot delete category with contacts. Remove contacts first."})
		return
	}

	if err := ctrl.DB.Delete(&models.ContactCategory{}, id).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete category"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Category deleted"})
}

// ==================== ADMIN: CONTACTS ====================

// GetContacts lists all contacts (admin)
func (ctrl *ContactInfoController) GetContacts(c *gin.Context) {
	var contacts []models.Contact
	if err := ctrl.DB.Preload("Category").
		Order("display_order ASC, created_at ASC").
		Find(&contacts).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load contacts"})
		return
	}

	c.JSON(http.StatusOK, contacts)
}

// CreateContact creates a new contact (admin)
func (ctrl *ContactInfoController) CreateContact(c *gin.Context) {
	var body struct {
		CategoryID   *uint  `json:"category_id"`
		Name         string `json:"name" binding:"required"`
		Position     string `json:"position"`
		Email        string `json:"email"`
		Phone        string `json:"phone"`
		ImageURL     string `json:"image_url"`
		Description  string `json:"description"`
		DisplayOrder *int   `json:"display_order"`
		IsActive     *bool  `json:"is_active"`
	}
	if err := c.ShouldBindJSON(&body); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	contact := models.Contact{
		CategoryID:  body.CategoryID,
		Name:        strings.TrimSpace(body.Name),
		Position:    strings.TrimSpace(body.Position),
		Email:       strings.TrimSpace(body.Email),
		Phone:       strings.TrimSpace(body.Phone),
		ImageURL:    strings.TrimSpace(body.ImageURL),
		Description: strings.TrimSpace(body.Description),
	}

	if body.DisplayOrder != nil {
		contact.DisplayOrder = *body.DisplayOrder
	}
	if body.IsActive != nil {
		contact.IsActive = *body.IsActive
	} else {
		contact.IsActive = true
	}

	// Validate category if provided
	if contact.CategoryID != nil {
		var cat models.ContactCategory
		if err := ctrl.DB.First(&cat, *contact.CategoryID).Error; err != nil {
			if err == gorm.ErrRecordNotFound {
				c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid category_id"})
				return
			}
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
			return
		}
	}

	if err := ctrl.DB.Create(&contact).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create contact"})
		return
	}

	// Reload with category
	ctrl.DB.Preload("Category").First(&contact, contact.ID)

	c.JSON(http.StatusCreated, contact)
}

// UpdateContact updates a contact (admin)
func (ctrl *ContactInfoController) UpdateContact(c *gin.Context) {
	id := c.Param("id")
	
	var contact models.Contact
	if err := ctrl.DB.First(&contact, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			c.JSON(http.StatusNotFound, gin.H{"error": "Contact not found"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
		return
	}

	var body struct {
		CategoryID   *uint   `json:"category_id"`
		Name         *string `json:"name"`
		Position     *string `json:"position"`
		Email        *string `json:"email"`
		Phone        *string `json:"phone"`
		ImageURL     *string `json:"image_url"`
		Description  *string `json:"description"`
		DisplayOrder *int    `json:"display_order"`
		IsActive     *bool   `json:"is_active"`
	}
	if err := c.ShouldBindJSON(&body); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Allow setting category to null by sending explicit null
	if c.Request.Header.Get("Content-Type") == "application/json" {
		var raw map[string]interface{}
		if err := c.ShouldBindJSON(&raw); err == nil {
			if _, exists := raw["category_id"]; exists {
				contact.CategoryID = body.CategoryID
			}
		}
	} else if body.CategoryID != nil {
		// Validate new category
		var cat models.ContactCategory
		if err := ctrl.DB.First(&cat, *body.CategoryID).Error; err != nil {
			if err == gorm.ErrRecordNotFound {
				c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid category_id"})
				return
			}
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
			return
		}
		contact.CategoryID = body.CategoryID
	}

	if body.Name != nil {
		contact.Name = strings.TrimSpace(*body.Name)
	}
	if body.Position != nil {
		contact.Position = strings.TrimSpace(*body.Position)
	}
	if body.Email != nil {
		contact.Email = strings.TrimSpace(*body.Email)
	}
	if body.Phone != nil {
		contact.Phone = strings.TrimSpace(*body.Phone)
	}
	if body.ImageURL != nil {
		contact.ImageURL = strings.TrimSpace(*body.ImageURL)
	}
	if body.Description != nil {
		contact.Description = strings.TrimSpace(*body.Description)
	}
	if body.DisplayOrder != nil {
		contact.DisplayOrder = *body.DisplayOrder
	}
	if body.IsActive != nil {
		contact.IsActive = *body.IsActive
	}

	if err := ctrl.DB.Save(&contact).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update contact"})
		return
	}

	// Reload with category
	ctrl.DB.Preload("Category").First(&contact, contact.ID)

	c.JSON(http.StatusOK, contact)
}

// DeleteContact deletes a contact (admin)
func (ctrl *ContactInfoController) DeleteContact(c *gin.Context) {
	id := c.Param("id")
	
	if err := ctrl.DB.Delete(&models.Contact{}, id).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete contact"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Contact deleted"})
}
