package storage

import (
	"net/http"

	"github.com/atlasos/calypso/internal/common/database"
	"github.com/atlasos/calypso/internal/common/logger"
	"github.com/atlasos/calypso/internal/tasks"
	"github.com/gin-gonic/gin"
)

// Handler handles storage-related API requests
type Handler struct {
	diskService *DiskService
	lvmService  *LVMService
	taskEngine  *tasks.Engine
	db          *database.DB
	logger      *logger.Logger
}

// NewHandler creates a new storage handler
func NewHandler(db *database.DB, log *logger.Logger) *Handler {
	return &Handler{
		diskService: NewDiskService(db, log),
		lvmService:  NewLVMService(db, log),
		taskEngine:  tasks.NewEngine(db, log),
		db:          db,
		logger:      log,
	}
}

// ListDisks lists all physical disks
func (h *Handler) ListDisks(c *gin.Context) {
	disks, err := h.diskService.DiscoverDisks(c.Request.Context())
	if err != nil {
		h.logger.Error("Failed to list disks", "error", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list disks"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"disks": disks})
}

// SyncDisks syncs discovered disks to database
func (h *Handler) SyncDisks(c *gin.Context) {
	userID, _ := c.Get("user_id")

	// Create async task
	taskID, err := h.taskEngine.CreateTask(c.Request.Context(),
		tasks.TaskTypeRescan, userID.(string), map[string]interface{}{
			"operation": "sync_disks",
		})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create task"})
		return
	}

	// Run sync in background
	go func() {
		ctx := c.Request.Context()
		h.taskEngine.StartTask(ctx, taskID)
		h.taskEngine.UpdateProgress(ctx, taskID, 50, "Discovering disks...")

		if err := h.diskService.SyncDisksToDatabase(ctx); err != nil {
			h.taskEngine.FailTask(ctx, taskID, err.Error())
			return
		}

		h.taskEngine.UpdateProgress(ctx, taskID, 100, "Disk sync completed")
		h.taskEngine.CompleteTask(ctx, taskID, "Disks synchronized successfully")
	}()

	c.JSON(http.StatusAccepted, gin.H{"task_id": taskID})
}

// ListVolumeGroups lists all volume groups
func (h *Handler) ListVolumeGroups(c *gin.Context) {
	vgs, err := h.lvmService.ListVolumeGroups(c.Request.Context())
	if err != nil {
		h.logger.Error("Failed to list volume groups", "error", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list volume groups"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"volume_groups": vgs})
}

// ListRepositories lists all repositories
func (h *Handler) ListRepositories(c *gin.Context) {
	repos, err := h.lvmService.ListRepositories(c.Request.Context())
	if err != nil {
		h.logger.Error("Failed to list repositories", "error", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list repositories"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"repositories": repos})
}

// GetRepository retrieves a repository by ID
func (h *Handler) GetRepository(c *gin.Context) {
	repoID := c.Param("id")

	repo, err := h.lvmService.GetRepository(c.Request.Context(), repoID)
	if err != nil {
		if err.Error() == "repository not found" {
			c.JSON(http.StatusNotFound, gin.H{"error": "repository not found"})
			return
		}
		h.logger.Error("Failed to get repository", "error", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get repository"})
		return
	}

	c.JSON(http.StatusOK, repo)
}

// CreateRepositoryRequest represents a repository creation request
type CreateRepositoryRequest struct {
	Name        string `json:"name" binding:"required"`
	Description string `json:"description"`
	VolumeGroup string `json:"volume_group" binding:"required"`
	SizeGB      int64  `json:"size_gb" binding:"required"`
}

// CreateRepository creates a new repository
func (h *Handler) CreateRepository(c *gin.Context) {
	var req CreateRepositoryRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
		return
	}

	userID, _ := c.Get("user_id")
	sizeBytes := req.SizeGB * 1024 * 1024 * 1024

	repo, err := h.lvmService.CreateRepository(
		c.Request.Context(),
		req.Name,
		req.VolumeGroup,
		sizeBytes,
		userID.(string),
	)
	if err != nil {
		h.logger.Error("Failed to create repository", "error", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, repo)
}

// DeleteRepository deletes a repository
func (h *Handler) DeleteRepository(c *gin.Context) {
	repoID := c.Param("id")

	if err := h.lvmService.DeleteRepository(c.Request.Context(), repoID); err != nil {
		if err.Error() == "repository not found" {
			c.JSON(http.StatusNotFound, gin.H{"error": "repository not found"})
			return
		}
		h.logger.Error("Failed to delete repository", "error", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "repository deleted successfully"})
}

