package services

import (
	"encoding/json"
	"fotbal-club/internal/models"
	"path/filepath"
	"strconv"
	"strings"

	"gorm.io/gorm"
)

// FileTracker provides utilities for tracking file usage
type FileTracker struct {
	DB *gorm.DB
}

// NewFileTracker creates a new file tracker instance
func NewFileTracker(db *gorm.DB) *FileTracker {
	return &FileTracker{DB: db}
}

// TrackFileUpload records a new uploaded file
func (ft *FileTracker) TrackFileUpload(filePath, fileURL, filename, mimeType string, fileSize int64, uploadedByID *uint) error {
	file := models.UploadedFile{
		Filename:     filename,
		FilePath:     filePath,
		FileURL:      fileURL,
		FileSize:     fileSize,
		MimeType:     mimeType,
		UploadedByID: uploadedByID,
	}
	
	return ft.DB.Create(&file).Error
}

// TrackFileUsage records or updates file usage for an entity
func (ft *FileTracker) TrackFileUsage(fileURL, entityType string, entityID uint, fieldName string) error {
	if fileURL == "" {
		return nil
	}
	
	// Find the file by URL
	var file models.UploadedFile
	if err := ft.DB.Where("file_url = ?", fileURL).First(&file).Error; err != nil {
		// File not found in database - skip tracking
		return nil
	}
	
	// Check if usage already exists
	var existingUsage models.FileUsage
	err := ft.DB.Where("file_id = ? AND entity_type = ? AND entity_id = ? AND field_name = ?",
		file.ID, entityType, entityID, fieldName).First(&existingUsage).Error
	
	if err == gorm.ErrRecordNotFound {
		// Create new usage record
		usage := models.FileUsage{
			FileID:     file.ID,
			EntityType: entityType,
			EntityID:   entityID,
			FieldName:  fieldName,
		}
		return ft.DB.Create(&usage).Error
	}
	
	return err
}

// RemoveFileUsage removes a file usage record
func (ft *FileTracker) RemoveFileUsage(fileURL, entityType string, entityID uint, fieldName string) error {
	if fileURL == "" {
		return nil
	}
	
	// Find the file by URL
	var file models.UploadedFile
	if err := ft.DB.Where("file_url = ?", fileURL).First(&file).Error; err != nil {
		return nil
	}
	
	return ft.DB.Where("file_id = ? AND entity_type = ? AND entity_id = ? AND field_name = ?",
		file.ID, entityType, entityID, fieldName).Delete(&models.FileUsage{}).Error
}

// UpdateFileUsages updates all file usages for an entity (removes old, adds new)
func (ft *FileTracker) UpdateFileUsages(entityType string, entityID uint, fieldURLMap map[string]string) error {
	// Get all current usages for this entity
	var currentUsages []models.FileUsage
	ft.DB.Where("entity_type = ? AND entity_id = ?", entityType, entityID).Find(&currentUsages)
	
	// Create a map of current usages
	currentMap := make(map[string]models.FileUsage)
	for _, usage := range currentUsages {
		key := usage.FieldName
		currentMap[key] = usage
	}
	
	// Track new usages
	for fieldName, fileURL := range fieldURLMap {
		if fileURL != "" {
			// Check if already tracked
			if _, exists := currentMap[fieldName]; !exists {
				ft.TrackFileUsage(fileURL, entityType, entityID, fieldName)
			}
			delete(currentMap, fieldName) // Remove from current map
		}
	}
	
	// Remove usages that are no longer present
	for fieldName := range currentMap {
		ft.DB.Where("entity_type = ? AND entity_id = ? AND field_name = ?",
			entityType, entityID, fieldName).Delete(&models.FileUsage{})
	}
	return nil
}

// TrackArticleFiles tracks all file usages in an article
func (ft *FileTracker) TrackArticleFiles(article *models.Article) error {
    fieldURLMap := map[string]string{
        "image_url": article.ImageURL,
        "og_image_url": article.OGImageURL,
    }
	
	// Track attachments if present
	if article.Attachments != "" {
		// Attachments is a JSON array of URLs - parse properly
		var attachmentURLs []string
		if err := json.Unmarshal([]byte(article.Attachments), &attachmentURLs); err == nil {
			// Successfully parsed as JSON array
			for i, attachmentURL := range attachmentURLs {
				if attachmentURL != "" {
					// Extract filename from URL for better field naming
					filename := filepath.Base(attachmentURL)
					fieldName := "attachment_" + filename
					// Ensure unique field names if same filename appears multiple times
					if _, exists := fieldURLMap[fieldName]; exists {
						fieldName = "attachment_" + filename + "_" + strconv.Itoa(i)
					}
					fieldURLMap[fieldName] = attachmentURL
				}
			}
		} else {
			// Fallback to simple comma-separated parsing
			attachments := strings.Split(article.Attachments, ",")
			for i, attachment := range attachments {
				attachment = strings.Trim(attachment, `[]" `)
				if attachment != "" {
					filename := filepath.Base(attachment)
					fieldName := "attachment_" + filename
					if _, exists := fieldURLMap[fieldName]; exists {
						fieldName = "attachment_" + filename + "_" + strconv.Itoa(i)
					}
					fieldURLMap[fieldName] = attachment
				}
			}
		}
	}
	
	return ft.UpdateFileUsages("article", article.ID, fieldURLMap)
}

// TrackPlayerFiles tracks all file usages in a player
func (ft *FileTracker) TrackPlayerFiles(player *models.Player) error {
	fieldURLMap := map[string]string{
		"image_url": player.ImageURL,
	}
	return ft.UpdateFileUsages("player", player.ID, fieldURLMap)
}

// TrackSponsorFiles tracks all file usages in a sponsor
func (ft *FileTracker) TrackSponsorFiles(sponsor *models.Sponsor) error {
	fieldURLMap := map[string]string{
		"logo_url": sponsor.LogoURL,
	}
	return ft.UpdateFileUsages("sponsor", sponsor.ID, fieldURLMap)
}

// TrackEventFiles tracks all file usages in an event
func (ft *FileTracker) TrackEventFiles(event *models.Event) error {
	fieldURLMap := map[string]string{
		"image_url": event.ImageURL,
		"file_url":  event.FileURL,
	}
	
	// Track each attachment separately
	for i, attachment := range event.Attachments {
		if attachment.URL != "" {
			// Generate field name from attachment name or filename
			fieldName := ""
			if attachment.Name != "" {
				// Use attachment name if available
				fieldName = "attachment_" + strings.ReplaceAll(attachment.Name, " ", "_")
			} else {
				// Fall back to filename from URL
				filename := filepath.Base(attachment.URL)
				fieldName = "attachment_" + filename
			}
			
			// Ensure unique field names if duplicates exist
			originalFieldName := fieldName
			for counter := 0; ; counter++ {
				if _, exists := fieldURLMap[fieldName]; !exists {
					break
				}
				// Add counter suffix if field name already exists
				fieldName = originalFieldName + "_" + strconv.Itoa(counter)
				if counter > 999 { // Prevent infinite loop
					fieldName = originalFieldName + "_" + strconv.Itoa(i)
					break
				}
			}
			
			fieldURLMap[fieldName] = attachment.URL
		}
	}
	
	return ft.UpdateFileUsages("event", event.ID, fieldURLMap)
}

// TrackContactFiles tracks all file usages in a contact
func (ft *FileTracker) TrackContactFiles(contact *models.Contact) error {
	fieldURLMap := map[string]string{
		"image_url": contact.ImageURL,
	}
	return ft.UpdateFileUsages("contact", contact.ID, fieldURLMap)
}

// TrackSettingsFiles tracks all file usages in settings
func (ft *FileTracker) TrackSettingsFiles(settings *models.Settings) error {
	fieldURLMap := map[string]string{
		"default_og_image_url": settings.DefaultOGImageURL,
		"club_logo_url":        settings.ClubLogoURL,
	}
	return ft.UpdateFileUsages("settings", settings.ID, fieldURLMap)
}

// TrackTeamFiles tracks all file usages in a team
func (ft *FileTracker) TrackTeamFiles(team *models.Team) error {
	fieldURLMap := map[string]string{
		"logo_url": team.LogoURL,
	}
	return ft.UpdateFileUsages("team", team.ID, fieldURLMap)
}
