package controllers

import (
	"net/http"
	"time"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"fotbal-club/internal/models"
	"fotbal-club/internal/services"
)

type EventController struct{ DB *gorm.DB }

// GetEventByID returns a single event by its ID (public; returns only public events unless owner)
func (ctrl *EventController) GetEventByID(c *gin.Context) {
    id := c.Param("id")
    var ev models.Event
    if err := ctrl.DB.Preload("Attachments").First(&ev, id).Error; err != nil {
        if err == gorm.ErrRecordNotFound {
            c.JSON(http.StatusNotFound, gin.H{"error": "Event not found"})
            return
        }
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
        return
    }
    // If not public, allow only owner (when identified upstream)
    if !ev.IsPublic {
        if userID, exists := c.Get("userID"); !exists || ev.CreatedByID != userID {
            c.JSON(http.StatusForbidden, gin.H{"error": "Not allowed"})
            return
        }
    }
    c.JSON(http.StatusOK, ev)
}

type EventInput struct {
    Title       string     `json:"title" binding:"required"`
    Description string     `json:"description"`
    StartTime   time.Time  `json:"start_time" binding:"required"`
    EndTime     *time.Time `json:"end_time"`
    Location    string     `json:"location"`
    Type        string     `json:"type" binding:"required,oneof=match training meeting other"`
    IsPublic    bool       `json:"is_public"`
    CategoryName string    `json:"category_name"`
    ImageURL    string     `json:"image_url"`
    FileURL     string     `json:"file_url"`
    YoutubeURL  string     `json:"youtube_url"`
    Latitude    *float64   `json:"latitude"`
    Longitude   *float64   `json:"longitude"`
    Attachments []struct {
        Name     string `json:"name"`
        URL      string `json:"url"`
        MimeType string `json:"mime_type"`
        Size     int64  `json:"size"`
    } `json:"attachments"`
}

func (ctrl *EventController) CreateEvent(c *gin.Context) {
    // Ensure latest schema (adds columns if missing)
    _ = ctrl.DB.AutoMigrate(&models.Event{}, &models.EventAttachment{})
    var input EventInput
    if err := c.ShouldBindJSON(&input); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    userID, _ := c.Get("userID")
    event := models.Event{
        Title:        input.Title,
        Description:  input.Description,
        StartTime:    input.StartTime,
        EndTime:      input.EndTime,
        Location:     input.Location,
        Type:         models.EventType(input.Type),
        IsPublic:     input.IsPublic,
        CreatedByID:  userID.(uint),
        CategoryName: input.CategoryName,
        ImageURL:     input.ImageURL,
        FileURL:      input.FileURL,
        YoutubeURL:   input.YoutubeURL,
        Latitude:     input.Latitude,
        Longitude:    input.Longitude,
    }

    if err := ctrl.DB.Create(&event).Error; err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create event"})
        return
    }
    // Create attachments if any
    if len(input.Attachments) > 0 {
        var atts []models.EventAttachment
        for _, a := range input.Attachments {
            if a.URL == "" { continue }
            atts = append(atts, models.EventAttachment{ EventID: event.ID, Name: a.Name, URL: a.URL, MimeType: a.MimeType, Size: a.Size })
        }
        if len(atts) > 0 {
            if err := ctrl.DB.Create(&atts).Error; err != nil {
                // non-fatal
            }
        }
    }

    // Reload with attachments
    var out models.Event
    _ = ctrl.DB.Preload("Attachments").First(&out, event.ID).Error
    
    // Track file usage
    fileTracker := services.NewFileTracker(ctrl.DB)
    go fileTracker.TrackEventFiles(&out)
    
    c.JSON(http.StatusCreated, out)
}

func (ctrl *EventController) GetEvents(c *gin.Context) {
	var events []models.Event
	query := ctrl.DB.Preload("Attachments")
	
	if userID, exists := c.Get("userID"); !exists {
		query = query.Where("is_public = ?", true)
	} else {
		query = query.Where("created_by_id = ? OR is_public = ?", userID, true)
	}

	if err := query.Find(&events).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch events"})
		return
	}

	c.JSON(http.StatusOK, events)
}

func (ctrl *EventController) GetUpcomingEvents(c *gin.Context) {
    var events []models.Event
    query := ctrl.DB.Preload("Attachments").Where("start_time >= ?", time.Now()).Order("start_time ASC").Limit(5)
	
	if userID, exists := c.Get("userID"); !exists {
		query = query.Where("is_public = ?", true)
	} else {
		query = query.Where("created_by_id = ? OR is_public = ?", userID, true)
	}

	if err := query.Find(&events).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch events"})
		return
	}

	c.JSON(http.StatusOK, events)
}

// UpdateEvent updates an existing event (protected)
func (ctrl *EventController) UpdateEvent(c *gin.Context) {
    // Ensure latest schema (adds columns if missing)
    _ = ctrl.DB.AutoMigrate(&models.Event{}, &models.EventAttachment{})
    id := c.Param("id")
    var ev models.Event
    if err := ctrl.DB.First(&ev, id).Error; err != nil {
        if err == gorm.ErrRecordNotFound {
            c.JSON(http.StatusNotFound, gin.H{"error": "Event not found"})
            return
        }
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
        return
    }
    var input EventInput
    if err := c.ShouldBindJSON(&input); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    ev.Title = input.Title
    ev.Description = input.Description
    ev.StartTime = input.StartTime
    ev.EndTime = input.EndTime
    ev.Location = input.Location
    ev.Type = models.EventType(input.Type)
    ev.IsPublic = input.IsPublic
    ev.CategoryName = input.CategoryName
    ev.ImageURL = input.ImageURL
    ev.FileURL = input.FileURL
    ev.YoutubeURL = input.YoutubeURL
    ev.Latitude = input.Latitude
    ev.Longitude = input.Longitude
    if err := ctrl.DB.Save(&ev).Error; err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update event"})
        return
    }
    // Replace attachments (simple strategy)
    if err := ctrl.DB.Where("event_id = ?", ev.ID).Delete(&models.EventAttachment{}).Error; err == nil {
        if len(input.Attachments) > 0 {
            var atts []models.EventAttachment
            for _, a := range input.Attachments {
                if a.URL == "" { continue }
                atts = append(atts, models.EventAttachment{ EventID: ev.ID, Name: a.Name, URL: a.URL, MimeType: a.MimeType, Size: a.Size })
            }
            if len(atts) > 0 {
                _ = ctrl.DB.Create(&atts).Error
            }
        }
    }
    var out models.Event
    _ = ctrl.DB.Preload("Attachments").First(&out, ev.ID).Error
    
    // Track file usage
    fileTracker := services.NewFileTracker(ctrl.DB)
    go fileTracker.TrackEventFiles(&out)
    
    c.JSON(http.StatusOK, out)
}

// DeleteEvent removes an event (protected)
func (ctrl *EventController) DeleteEvent(c *gin.Context) {
    id := c.Param("id")
    if err := ctrl.DB.Delete(&models.Event{}, id).Error; err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete event"})
        return
    }
    c.JSON(http.StatusOK, gin.H{"ok": true})
}
