package controllers

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strconv"

	"fitra-backend/utils"

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

func generateID() (string, error) {
	bytes := make([]byte, 16)
	_, err := rand.Read(bytes)
	return hex.EncodeToString(bytes), err
}

func HandleFileUpload(c *gin.Context) {
	// Try to get a single file first (backward compatibility)
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "No file provided"})
		return
	}
	defer file.Close()

	// Resolve upload directory from environment
	uploadDir := os.Getenv("UPLOAD_DIR")
	if uploadDir == "" {
		uploadDir = "./uploads"
	}

	// Ensure upload directory exists (so size calc works)
	if _, err := os.Stat(uploadDir); os.IsNotExist(err) {
		if err := os.MkdirAll(uploadDir, 0755); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create upload directory"})
			return
		}
	}

	// Read max storage from env and compute current usage
	maxStorageEnv := os.Getenv("MAX_STORAGE_GB")
	if maxStorageEnv == "" {
		maxStorageEnv = "10"
	}
	maxStorageGB, err := strconv.ParseFloat(maxStorageEnv, 64)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid MAX_STORAGE_GB configuration"})
		return
	}

	usedBytes, err := getDirectorySize(uploadDir)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to calculate storage usage"})
		return
	}
	maxBytes := int64(maxStorageGB * 1024 * 1024 * 1024)

	// If storage is already full, reject upload
	if usedBytes >= maxBytes {
		c.JSON(http.StatusInsufficientStorage, gin.H{"error": "Storage limit reached. Upload disabled."})
		return
	}
	// If this file would exceed the limit (when size is known), reject upload
	if header.Size > 0 && usedBytes+header.Size > maxBytes {
		c.JSON(http.StatusInsufficientStorage, gin.H{"error": "Not enough storage available for this upload."})
		return
	}

	fileID, err := generateID()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate file ID"})
		return
	}

	fileDir := filepath.Join(uploadDir, fileID)
	if err := os.MkdirAll(fileDir, 0755); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create file directory"})
		return
	}

	out, err := os.Create(filepath.Join(fileDir, header.Filename))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create file"})
		return
	}
	defer out.Close()

	if _, err = io.Copy(out, file); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file"})
		return
	}

	baseURL := os.Getenv("BASE_URL")
	if baseURL == "" {
		baseURL = "http://localhost:8080"
	}

	// Send analytics event
	properties := fmt.Sprintf(`{"filename": "%s", "size": %d}`, header.Filename, header.Size)
	utils.SendCustomEvent("file_upload", "/api/upload", properties)

	c.JSON(http.StatusOK, gin.H{
		"message":  "File uploaded successfully",
		"id":       fileID,
		"filename": header.Filename,
		"size":     header.Size,
		"url":      baseURL + "/uploads/" + fileID + "/" + header.Filename,
	})
}
