package controllers

import (
	"fotbal-club/internal/models"
	"net/http"
	"strconv"

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

type NavigationController struct {
	DB *gorm.DB
}

func NewNavigationController(db *gorm.DB) *NavigationController {
	return &NavigationController{DB: db}
}

// GetNavigationItems returns all navigation items (public endpoint)
// @Summary Get all navigation items
// @Description Returns all visible navigation items with their children (excludes admin-only items)
// @Tags navigation
// @Produce json
// @Success 200 {array} models.NavigationItem
// @Router /api/v1/navigation [get]
func (nc *NavigationController) GetNavigationItems(c *gin.Context) {
	var items []models.NavigationItem
	
	// Get only top-level items (no parent) that are visible and NOT admin-only
	if err := nc.DB.Where("parent_id IS NULL AND visible = ? AND requires_admin = ?", true, false).
		Order("display_order ASC").
		Preload("Children", "visible = ? AND requires_admin = ?", true, false).
		Find(&items).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch navigation items"})
		return
	}
	
	// Compute URLs for items
	for i := range items {
		if items[i].URL == "" {
			items[i].URL = items[i].GetURL()
		}
		for j := range items[i].Children {
			if items[i].Children[j].URL == "" {
				items[i].Children[j].URL = items[i].Children[j].GetURL()
			}
		}
	}
	
	c.JSON(http.StatusOK, items)
}

// GetAllNavigationItems returns all navigation items including hidden ones (admin only)
// @Summary Get all navigation items (admin)
// @Description Returns all navigation items for admin management
// @Tags navigation
// @Produce json
// @Security BearerAuth
// @Success 200 {array} models.NavigationItem
// @Router /api/v1/admin/navigation [get]
func (nc *NavigationController) GetAllNavigationItems(c *gin.Context) {
	var items []models.NavigationItem
	
	if err := nc.DB.Where("parent_id IS NULL").
		Order("display_order ASC").
		Preload("Children", func(db *gorm.DB) *gorm.DB {
			return db.Order("display_order ASC")
		}).
		Find(&items).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch navigation items"})
		return
	}
	
	// Compute URLs for items
	for i := range items {
		if items[i].URL == "" {
			items[i].URL = items[i].GetURL()
		}
		for j := range items[i].Children {
			if items[i].Children[j].URL == "" {
				items[i].Children[j].URL = items[i].Children[j].GetURL()
			}
		}
	}
	
	c.JSON(http.StatusOK, items)
}

// CreateNavigationItem creates a new navigation item
// @Summary Create navigation item
// @Description Creates a new navigation item
// @Tags navigation
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param item body models.NavigationItem true "Navigation item data"
// @Success 201 {object} models.NavigationItem
// @Router /api/v1/admin/navigation [post]
func (nc *NavigationController) CreateNavigationItem(c *gin.Context) {
	var item models.NavigationItem
	
	if err := c.ShouldBindJSON(&item); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	// If no display order is set, put it at the end
	if item.DisplayOrder == 0 {
		var maxOrder int
		query := nc.DB.Model(&models.NavigationItem{})
		
		// Calculate max order for items at the same level (same parent) and same admin status
		if item.ParentID == nil {
			query = query.Where("parent_id IS NULL")
		} else {
			query = query.Where("parent_id = ?", *item.ParentID)
		}
		
		// Also consider requires_admin to keep frontend and admin items separate
		query = query.Where("requires_admin = ?", item.RequiresAdmin)
		
		query.Select("COALESCE(MAX(display_order), -1) + 1").Scan(&maxOrder)
		item.DisplayOrder = maxOrder
	}
	
	if err := nc.DB.Create(&item).Error; err != nil {
		// Log the actual error for debugging
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "Failed to create navigation item",
			"details": err.Error(),
		})
		return
	}
	
	c.JSON(http.StatusCreated, item)
}

// UpdateNavigationItem updates an existing navigation item
// @Summary Update navigation item
// @Description Updates an existing navigation item
// @Tags navigation
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "Navigation item ID"
// @Param item body models.NavigationItem true "Updated navigation item data"
// @Success 200 {object} models.NavigationItem
// @Router /api/v1/admin/navigation/{id} [put]
func (nc *NavigationController) UpdateNavigationItem(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
		return
	}
	
	var item models.NavigationItem
	if err := nc.DB.First(&item, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Navigation item not found"})
		return
	}
	
	var updates models.NavigationItem
	if err := c.ShouldBindJSON(&updates); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	// Update fields
	item.Label = updates.Label
	item.URL = updates.URL
	item.Icon = updates.Icon
	item.Type = updates.Type
	item.PageType = updates.PageType
	item.PageID = updates.PageID
	item.Visible = updates.Visible
	item.DisplayOrder = updates.DisplayOrder
	item.ParentID = updates.ParentID
	item.Target = updates.Target
	item.CSSClass = updates.CSSClass
	item.RequiresAuth = updates.RequiresAuth
	item.RequiresAdmin = updates.RequiresAdmin
	
	if err := nc.DB.Save(&item).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "Failed to update navigation item",
			"details": err.Error(),
		})
		return
	}
	
	c.JSON(http.StatusOK, item)
}

// DeleteNavigationItem deletes a navigation item
// @Summary Delete navigation item
// @Description Deletes a navigation item
// @Tags navigation
// @Produce json
// @Security BearerAuth
// @Param id path int true "Navigation item ID"
// @Success 200 {object} map[string]string
// @Router /api/v1/admin/navigation/{id} [delete]
func (nc *NavigationController) DeleteNavigationItem(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
		return
	}
	
	if err := nc.DB.Delete(&models.NavigationItem{}, id).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete navigation item"})
		return
	}
	
	c.JSON(http.StatusOK, gin.H{"message": "Navigation item deleted successfully"})
}

// ReorderNavigationItems updates the display order of multiple items
// @Summary Reorder navigation items
// @Description Updates the display order of navigation items
// @Tags navigation
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param orders body []map[string]int true "Array of {id, display_order}"
// @Success 200 {object} map[string]string
// @Router /api/v1/admin/navigation/reorder [post]
func (nc *NavigationController) ReorderNavigationItems(c *gin.Context) {
	var orders []map[string]int
	if err := c.ShouldBindJSON(&orders); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	// Update each item's order in a transaction
	err := nc.DB.Transaction(func(tx *gorm.DB) error {
		for _, order := range orders {
			id, ok1 := order["id"]
			displayOrder, ok2 := order["display_order"]
			if !ok1 || !ok2 {
				continue
			}
			
			if err := tx.Model(&models.NavigationItem{}).
				Where("id = ?", id).
				Update("display_order", displayOrder).Error; err != nil {
				return err
			}
		}
		return nil
	})
	
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to reorder navigation items"})
		return
	}
	
	c.JSON(http.StatusOK, gin.H{"message": "Navigation items reordered successfully"})
}

// GetSocialLinks returns all social links (public endpoint)
// @Summary Get all social links
// @Description Returns all visible social links
// @Tags navigation
// @Produce json
// @Success 200 {array} models.SocialLink
// @Router /api/v1/social-links [get]
func (nc *NavigationController) GetSocialLinks(c *gin.Context) {
	var links []models.SocialLink
	
	if err := nc.DB.Where("visible = ?", true).
		Order("display_order ASC").
		Find(&links).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch social links"})
		return
	}
	
	c.JSON(http.StatusOK, links)
}

// GetAllSocialLinks returns all social links including hidden ones (admin only)
// @Summary Get all social links (admin)
// @Description Returns all social links for admin management
// @Tags navigation
// @Produce json
// @Security BearerAuth
// @Success 200 {array} models.SocialLink
// @Router /api/v1/admin/social-links [get]
func (nc *NavigationController) GetAllSocialLinks(c *gin.Context) {
	var links []models.SocialLink
	
	if err := nc.DB.Order("display_order ASC").Find(&links).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch social links"})
		return
	}
	
	c.JSON(http.StatusOK, links)
}

// CreateSocialLink creates a new social link
// @Summary Create social link
// @Description Creates a new social link
// @Tags navigation
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param link body models.SocialLink true "Social link data"
// @Success 201 {object} models.SocialLink
// @Router /api/v1/admin/social-links [post]
func (nc *NavigationController) CreateSocialLink(c *gin.Context) {
	var link models.SocialLink
	
	if err := c.ShouldBindJSON(&link); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	// If no display order is set, put it at the end
	if link.DisplayOrder == 0 {
		var maxOrder int
		nc.DB.Model(&models.SocialLink{}).
			Select("COALESCE(MAX(display_order), -1) + 1").
			Scan(&maxOrder)
		link.DisplayOrder = maxOrder
	}
	
	if err := nc.DB.Create(&link).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create social link"})
		return
	}
	
	c.JSON(http.StatusCreated, link)
}

// UpdateSocialLink updates an existing social link
// @Summary Update social link
// @Description Updates an existing social link
// @Tags navigation
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "Social link ID"
// @Param link body models.SocialLink true "Updated social link data"
// @Success 200 {object} models.SocialLink
// @Router /api/v1/admin/social-links/{id} [put]
func (nc *NavigationController) UpdateSocialLink(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
		return
	}
	
	var link models.SocialLink
	if err := nc.DB.First(&link, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Social link not found"})
		return
	}
	
	var updates models.SocialLink
	if err := c.ShouldBindJSON(&updates); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	link.Platform = updates.Platform
	link.URL = updates.URL
	link.DisplayOrder = updates.DisplayOrder
	link.Visible = updates.Visible
	link.Icon = updates.Icon
	
	if err := nc.DB.Save(&link).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update social link"})
		return
	}
	
	c.JSON(http.StatusOK, link)
}

// DeleteSocialLink deletes a social link
// @Summary Delete social link
// @Description Deletes a social link
// @Tags navigation
// @Produce json
// @Security BearerAuth
// @Param id path int true "Social link ID"
// @Success 200 {object} map[string]string
// @Router /api/v1/admin/social-links/{id} [delete]
func (nc *NavigationController) DeleteSocialLink(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
		return
	}
	
	if err := nc.DB.Delete(&models.SocialLink{}, id).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete social link"})
		return
	}
	
	c.JSON(http.StatusOK, gin.H{"message": "Social link deleted successfully"})
}

// ReorderSocialLinks updates the display order of multiple social links
// @Summary Reorder social links
// @Description Updates the display order of social links
// @Tags navigation
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param orders body []map[string]int true "Array of {id, display_order}"
// @Success 200 {object} map[string]string
// @Router /api/v1/admin/social-links/reorder [post]
func (nc *NavigationController) ReorderSocialLinks(c *gin.Context) {
	var orders []map[string]int
	if err := c.ShouldBindJSON(&orders); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	err := nc.DB.Transaction(func(tx *gorm.DB) error {
		for _, order := range orders {
			id, ok1 := order["id"]
			displayOrder, ok2 := order["display_order"]
			if !ok1 || !ok2 {
				continue
			}
			
			if err := tx.Model(&models.SocialLink{}).
				Where("id = ?", id).
				Update("display_order", displayOrder).Error; err != nil {
				return err
			}
		}
		return nil
	})
	
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to reorder social links"})
		return
	}
	
	c.JSON(http.StatusOK, gin.H{"message": "Social links reordered successfully"})
}

// SeedDefaultNavigation creates default navigation items if none exist
// @Summary Seed default navigation
// @Description Creates default navigation items if the database is empty
// @Tags navigation
// @Produce json
// @Security BearerAuth
// @Success 200 {object} map[string]interface{}
// @Router /api/v1/admin/navigation/seed [post]
func (nc *NavigationController) SeedDefaultNavigation(c *gin.Context) {
	// Check if navigation items already exist
	var count int64
	nc.DB.Model(&models.NavigationItem{}).Count(&count)
	
	if count > 0 {
		c.JSON(http.StatusOK, gin.H{
			"message": "Navigation items already exist",
			"count":   count,
			"seeded":  false,
		})
		return
	}
	
	// Default frontend navigation items
	frontendItems := []models.NavigationItem{
		{Label: "Domů", Type: models.NavTypePage, PageType: "home", DisplayOrder: 0, Visible: true, RequiresAdmin: false},
		{Label: "O klubu", Type: models.NavTypePage, PageType: "about", DisplayOrder: 1, Visible: true, RequiresAdmin: false},
		{Label: "Kalendář", Type: models.NavTypePage, PageType: "calendar", DisplayOrder: 2, Visible: true, RequiresAdmin: false},
		{Label: "Zápasy", Type: models.NavTypePage, PageType: "matches", DisplayOrder: 3, Visible: true, RequiresAdmin: false},
		{Label: "Aktivity", Type: models.NavTypePage, PageType: "activities", DisplayOrder: 4, Visible: true, RequiresAdmin: false},
		{Label: "Hráči", Type: models.NavTypePage, PageType: "players", DisplayOrder: 5, Visible: true, RequiresAdmin: false},
		{Label: "Tabulky", Type: models.NavTypePage, PageType: "tables", DisplayOrder: 6, Visible: true, RequiresAdmin: false},
		{Label: "Články", Type: models.NavTypePage, PageType: "blog", DisplayOrder: 7, Visible: true, RequiresAdmin: false},
		{Label: "Videa", Type: models.NavTypePage, PageType: "videos", DisplayOrder: 8, Visible: true, RequiresAdmin: false},
		{Label: "Fotogalerie", Type: models.NavTypePage, PageType: "gallery", DisplayOrder: 9, Visible: true, RequiresAdmin: false},
		{Label: "Sponzoři", Type: models.NavTypePage, PageType: "sponsors", DisplayOrder: 10, Visible: true, RequiresAdmin: false},
		{Label: "Kontakt", Type: models.NavTypePage, PageType: "contact", DisplayOrder: 11, Visible: true, RequiresAdmin: false},
	}
	
	// Default admin panel navigation items
	adminItems := []models.NavigationItem{
		// Main section
		{Label: "Nástěnka", Type: models.NavTypeInternal, PageType: "dashboard", DisplayOrder: 0, Visible: true, RequiresAdmin: true},
		{Label: "Analytika", Type: models.NavTypeInternal, PageType: "analytics", DisplayOrder: 1, Visible: true, RequiresAdmin: true},
		
		// Content section
		{Label: "Týmy", Type: models.NavTypeInternal, PageType: "teams", DisplayOrder: 2, Visible: true, RequiresAdmin: true},
		{Label: "Zápasy", Type: models.NavTypeInternal, PageType: "matches", DisplayOrder: 3, Visible: true, RequiresAdmin: true},
		{Label: "Aktivity", Type: models.NavTypeInternal, PageType: "activities", DisplayOrder: 4, Visible: true, RequiresAdmin: true},
		{Label: "Hráči", Type: models.NavTypeInternal, PageType: "players", DisplayOrder: 5, Visible: true, RequiresAdmin: true},
		{Label: "Články", Type: models.NavTypeInternal, PageType: "articles", DisplayOrder: 6, Visible: true, RequiresAdmin: true},
		{Label: "Kategorie", Type: models.NavTypeInternal, PageType: "categories", DisplayOrder: 7, Visible: true, RequiresAdmin: true},
		{Label: "O klubu", Type: models.NavTypeInternal, PageType: "about", DisplayOrder: 8, Visible: true, RequiresAdmin: true},
		{Label: "Videa", Type: models.NavTypeInternal, PageType: "videos", DisplayOrder: 9, Visible: true, RequiresAdmin: true},
		{Label: "Galerie (Zonerama)", Type: models.NavTypeInternal, PageType: "gallery", DisplayOrder: 10, Visible: true, RequiresAdmin: true},
		{Label: "Tabule (Scoreboard)", Type: models.NavTypeInternal, PageType: "scoreboard", DisplayOrder: 11, Visible: true, RequiresAdmin: true},
		{Label: "Scoreboard Remote", Type: models.NavTypeInternal, PageType: "scoreboard_remote", DisplayOrder: 12, Visible: true, RequiresAdmin: true},
		{Label: "Oblečení", Type: models.NavTypeInternal, PageType: "clothing", DisplayOrder: 13, Visible: true, RequiresAdmin: true},
		{Label: "Sponzoři", Type: models.NavTypeInternal, PageType: "sponsors", DisplayOrder: 14, Visible: true, RequiresAdmin: true},
		{Label: "Bannery", Type: models.NavTypeInternal, PageType: "banners", DisplayOrder: 15, Visible: true, RequiresAdmin: true},
		{Label: "Zprávy", Type: models.NavTypeInternal, PageType: "messages", DisplayOrder: 16, Visible: true, RequiresAdmin: true},
		{Label: "Kontakty", Type: models.NavTypeInternal, PageType: "contacts", DisplayOrder: 17, Visible: true, RequiresAdmin: true},
		{Label: "Zpravodaj", Type: models.NavTypeInternal, PageType: "newsletter", DisplayOrder: 18, Visible: true, RequiresAdmin: true},
		{Label: "Ankety", Type: models.NavTypeInternal, PageType: "polls", DisplayOrder: 19, Visible: true, RequiresAdmin: true},
		
		// Settings section
		{Label: "Navigace", Type: models.NavTypeInternal, PageType: "navigation", DisplayOrder: 20, Visible: true, RequiresAdmin: true},
		{Label: "Alias soutěží", Type: models.NavTypeInternal, PageType: "competition_aliases", DisplayOrder: 21, Visible: true, RequiresAdmin: true},
		{Label: "Prefetch & Cache", Type: models.NavTypeInternal, PageType: "prefetch", DisplayOrder: 22, Visible: true, RequiresAdmin: true},
		{Label: "Uživatelé", Type: models.NavTypeInternal, PageType: "users", DisplayOrder: 23, Visible: true, RequiresAdmin: true},
		{Label: "Nastavení", Type: models.NavTypeInternal, PageType: "settings", DisplayOrder: 24, Visible: true, RequiresAdmin: true},
		{Label: "Soubory", Type: models.NavTypeInternal, PageType: "files", DisplayOrder: 25, Visible: true, RequiresAdmin: true},
		
		// Help section
		{Label: "Dokumentace", Type: models.NavTypeInternal, PageType: "docs", DisplayOrder: 26, Visible: true, RequiresAdmin: true},
	}
	
	// Combine all items
	allItems := append(frontendItems, adminItems...)
	
	// Create items in a transaction
	err := nc.DB.Transaction(func(tx *gorm.DB) error {
		for _, item := range allItems {
			if err := tx.Create(&item).Error; err != nil {
				return err
			}
		}
		return nil
	})
	
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to seed navigation items"})
		return
	}
	
	c.JSON(http.StatusOK, gin.H{
		"message": "Default navigation items created successfully",
		"count":   len(allItems),
		"frontend_count": len(frontendItems),
		"admin_count": len(adminItems),
		"seeded":  true,
	})
}
