package controllers

import (
	"fmt"
	"fotbal-club/internal/models"
	"fotbal-club/internal/services"
	"fotbal-club/pkg/logger"
	"net/http"
	"os"
	"strings"
	"time"

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

// ArticleController handles article-related requests
type ArticleController struct {
	DB *gorm.DB
}

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

// CreateArticleRequest represents the request body for creating an article
type CreateArticleRequest struct {
	Title              string   `json:"title" binding:"required"`
	Content            string   `json:"content" binding:"required"`
	CategoryID         *uint    `json:"category_id"`
	CategoryName       string   `json:"category_name"`
	ImageURL           string   `json:"image_url"`
	Published          *bool    `json:"published"`
	PublishedAt        *string  `json:"published_at"`
	Featured           *bool    `json:"featured"`
	Slug               string   `json:"slug"`
	SeoTitle           string   `json:"seo_title"`
	SeoDescription     string   `json:"seo_description"`
	OgImageURL         string   `json:"og_image_url"`
	GalleryAlbumID     string   `json:"gallery_album_id"`
	GalleryAlbumURL    string   `json:"gallery_album_url"`
	GalleryPhotoIDs    []string `json:"gallery_photo_ids"`
	YouTubeVideoID        string   `json:"youtube_video_id"`
	YouTubeVideoTitle     string   `json:"youtube_video_title"`
	YouTubeVideoURL       string   `json:"youtube_video_url"`
	YouTubeVideoThumbnail string   `json:"youtube_video_thumbnail"`
}

// CreateArticle creates a new article with comprehensive error handling
func (ac *ArticleController) CreateArticle(c *gin.Context) {
	// 1. Check authentication
	uVal, ok := c.Get("user")
	if !ok {
		logger.Error("CreateArticle: User not authenticated")
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Uživatel není přihlášen"})
		return
	}
	user, ok := uVal.(*models.User)
	if !ok || user == nil {
		logger.Error("CreateArticle: Invalid user object in context")
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Neplatný uživatel"})
		return
	}

	logger.Info("CreateArticle: Request from user %d (%s)", user.ID, user.Email)

	// 2. Parse and validate request body
	var req CreateArticleRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.Error("CreateArticle: Invalid request body: %v", err)
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "Neplatná data požadavku",
			"details": err.Error(),
		})
		return
	}

	// Log the request
	logger.Info("CreateArticle: Creating article '%s' by user %d", req.Title, user.ID)

	// 3. Generate or validate slug
	slug := strings.TrimSpace(req.Slug)
	if slug == "" {
		slug = makeSlug(req.Title)
		logger.Info("CreateArticle: Generated slug '%s' from title", slug)
	}
	if slug == "" {
		slug = fmt.Sprintf("article-%d", time.Now().Unix())
		logger.Warn("CreateArticle: Using fallback slug '%s'", slug)
	}

	// 4. Ensure unique slug
	originalSlug := slug
	for i := 0; i < 50; i++ {
		var count int64
		if err := ac.DB.Model(&models.Article{}).Where("slug = ?", slug).Count(&count).Error; err != nil {
			logger.Error("CreateArticle: Error checking slug uniqueness: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Chyba při kontrole jedinečnosti URL"})
			return
		}
		if count == 0 {
			break
		}
		slug = fmt.Sprintf("%s-%d", originalSlug, i+1)
		logger.Info("CreateArticle: Slug collision, trying '%s'", slug)
	}

	// 5. Resolve or create category
	var categoryID *uint
	if req.CategoryID != nil && *req.CategoryID > 0 {
		categoryID = req.CategoryID
		logger.Info("CreateArticle: Using category ID %d", *categoryID)
	} else if strings.TrimSpace(req.CategoryName) != "" {
		categoryName := strings.TrimSpace(req.CategoryName)
		var category models.Category
		err := ac.DB.Where("name = ?", categoryName).First(&category).Error
		if err == gorm.ErrRecordNotFound {
			// Create new category
			category = models.Category{Name: categoryName}
			if err := ac.DB.Create(&category).Error; err != nil {
				logger.Error("CreateArticle: Error creating category '%s': %v", categoryName, err)
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Nelze vytvořit kategorii"})
				return
			}
			logger.Info("CreateArticle: Created new category '%s' with ID %d", categoryName, category.ID)
		} else if err != nil {
			logger.Error("CreateArticle: Error finding category: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Chyba při hledání kategorie"})
			return
		}
		catID := category.ID
		categoryID = &catID
	}

	// 6. Set published status and published_at
	published := false
	if req.Published != nil {
		published = *req.Published
	}
	var publishedAt *time.Time
	if req.PublishedAt != nil && strings.TrimSpace(*req.PublishedAt) != "" {
		if t, err := time.Parse(time.RFC3339, *req.PublishedAt); err == nil {
			publishedAt = &t
		} else {
			logger.Warn("CreateArticle: Could not parse published_at: %v", err)
		}
	}
	if published && publishedAt == nil {
		now := time.Now()
		publishedAt = &now
	}

	// 7. Set featured status
	featured := false
	if req.Featured != nil {
		featured = *req.Featured
	}

	// 8. Calculate estimated read time
	readTime := computeEstimatedReadMinutes(req.Content)
	logger.Info("CreateArticle: Estimated read time: %d minutes", readTime)

	// 9. Prepare SEO fields with fallbacks
	seoTitle := strings.TrimSpace(req.SeoTitle)
	if seoTitle == "" {
		seoTitle = strings.TrimSpace(req.Title)
	}
	seoDesc := strings.TrimSpace(req.SeoDescription)
	if seoDesc == "" {
		seoDesc = deriveSeoDescription(req.Content)
	}

	// 10. Set default image if empty
	imageURL := strings.TrimSpace(req.ImageURL)
	if imageURL == "" {
		imageURL = "/dist/img/logo-club-empty.svg"
		logger.Info("CreateArticle: Using default image")
	}

	// 11. Create the article object
	authorID := user.ID
	article := models.Article{
		Title:          strings.TrimSpace(req.Title),
		Content:        req.Content,
		AuthorID:       &authorID,
		CategoryID:     categoryID,
		Published:      published,
		PublishedAt:    publishedAt,
		ImageURL:       imageURL,
		ReadTime:       readTime,
		Slug:           slug,
		SEOTitle:       seoTitle,
		SEODescription: seoDesc,
		Featured:       featured,
	}

	// 12. Set optional OG image
	if trimmed := strings.TrimSpace(req.OgImageURL); trimmed != "" {
		article.OGImageURL = trimmed
	}

	// 13. Set gallery fields
	if trimmed := strings.TrimSpace(req.GalleryAlbumID); trimmed != "" {
		article.GalleryAlbumID = trimmed
	}
	if trimmed := strings.TrimSpace(req.GalleryAlbumURL); trimmed != "" {
		article.GalleryAlbumURL = trimmed
	}
	if len(req.GalleryPhotoIDs) > 0 {
		article.GalleryPhotoIDs = strings.Join(req.GalleryPhotoIDs, ",")
	}

	// 14. Set YouTube fields
	if trimmed := strings.TrimSpace(req.YouTubeVideoID); trimmed != "" {
		article.YouTubeVideoID = trimmed
	}
	if trimmed := strings.TrimSpace(req.YouTubeVideoTitle); trimmed != "" {
		article.YouTubeVideoTitle = trimmed
	}
	if trimmed := strings.TrimSpace(req.YouTubeVideoURL); trimmed != "" {
		article.YouTubeVideoURL = trimmed
	}
	if trimmed := strings.TrimSpace(req.YouTubeVideoThumbnail); trimmed != "" {
		article.YouTubeVideoThumbnail = trimmed
	}

	// 15. Save to database
	if err := ac.DB.Create(&article).Error; err != nil {
		logger.Error("CreateArticle: Database error: %v", err)
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "Nelze vytvořit článek",
			"details": err.Error(),
		})
		return
	}

	logger.Info("CreateArticle: Successfully created article ID=%d, slug=%s", article.ID, article.Slug)

	// 16. Track file usage (async)
	go func() {
		fileTracker := services.NewFileTracker(ac.DB)
		fileTracker.TrackArticleFiles(&article)
	}()

	// 17. Reload with associations for response
	ac.DB.Preload("Author").Preload("Category").First(&article, article.ID)

	// 18. Trigger prefetch cache update (async)
	if published {
		go func() {
			base := getBaseURL()
			logger.Info("CreateArticle: Triggering prefetch cache update for published article")
			services.PrefetchOnce(base)
		}()
	}

	// 19. Return success response
	c.JSON(http.StatusCreated, article)
}

// getBaseURL returns the base URL for internal API calls (used for prefetch trigger)
func getBaseURL() string {
	base := strings.TrimSpace(os.Getenv("PREFETCH_TARGET"))
	if base == "" {
		port := strings.TrimSpace(os.Getenv("PORT"))
		if port == "" {
			port = "8080"
		}
		base = "http://127.0.0.1:" + port + "/api/v1"
	}
	return base
}

// Note: Helper functions makeSlug, computeEstimatedReadMinutes, and deriveSeoDescription
// are defined in base_controller.go and shared across the controllers package
