package scst

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 SCST-related API requests
type Handler struct {
	service   *Service
	taskEngine *tasks.Engine
	db        *database.DB
	logger    *logger.Logger
}

// NewHandler creates a new SCST handler
func NewHandler(db *database.DB, log *logger.Logger) *Handler {
	return &Handler{
		service:   NewService(db, log),
		taskEngine: tasks.NewEngine(db, log),
		db:        db,
		logger:    log,
	}
}

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

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

// GetTarget retrieves a target by ID
func (h *Handler) GetTarget(c *gin.Context) {
	targetID := c.Param("id")

	target, err := h.service.GetTarget(c.Request.Context(), targetID)
	if err != nil {
		if err.Error() == "target not found" {
			c.JSON(http.StatusNotFound, gin.H{"error": "target not found"})
			return
		}
		h.logger.Error("Failed to get target", "error", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get target"})
		return
	}

	// Get LUNs
	luns, _ := h.service.GetTargetLUNs(c.Request.Context(), targetID)

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

// CreateTargetRequest represents a target creation request
type CreateTargetRequest struct {
	IQN                string `json:"iqn" binding:"required"`
	TargetType         string `json:"target_type" binding:"required"`
	Name               string `json:"name" binding:"required"`
	Description        string `json:"description"`
	SingleInitiatorOnly bool  `json:"single_initiator_only"`
}

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

	userID, _ := c.Get("user_id")

	target := &Target{
		IQN:                req.IQN,
		TargetType:         req.TargetType,
		Name:               req.Name,
		Description:        req.Description,
		IsActive:           true,
		SingleInitiatorOnly: req.SingleInitiatorOnly || req.TargetType == "vtl" || req.TargetType == "physical_tape",
		CreatedBy:          userID.(string),
	}

	if err := h.service.CreateTarget(c.Request.Context(), target); err != nil {
		h.logger.Error("Failed to create target", "error", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, target)
}

// AddLUNRequest represents a LUN addition request
type AddLUNRequest struct {
	DeviceName string `json:"device_name" binding:"required"`
	DevicePath string `json:"device_path" binding:"required"`
	LUNNumber  int    `json:"lun_number" binding:"required"`
	HandlerType string `json:"handler_type" binding:"required"`
}

// AddLUN adds a LUN to a target
func (h *Handler) AddLUN(c *gin.Context) {
	targetID := c.Param("id")

	target, err := h.service.GetTarget(c.Request.Context(), targetID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "target not found"})
		return
	}

	var req AddLUNRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
		return
	}

	if err := h.service.AddLUN(c.Request.Context(), target.IQN, req.DeviceName, req.DevicePath, req.LUNNumber, req.HandlerType); err != nil {
		h.logger.Error("Failed to add LUN", "error", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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

// AddInitiatorRequest represents an initiator addition request
type AddInitiatorRequest struct {
	InitiatorIQN string `json:"initiator_iqn" binding:"required"`
}

// AddInitiator adds an initiator to a target
func (h *Handler) AddInitiator(c *gin.Context) {
	targetID := c.Param("id")

	target, err := h.service.GetTarget(c.Request.Context(), targetID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "target not found"})
		return
	}

	var req AddInitiatorRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
		return
	}

	if err := h.service.AddInitiator(c.Request.Context(), target.IQN, req.InitiatorIQN); err != nil {
		h.logger.Error("Failed to add initiator", "error", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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

// ApplyConfig applies SCST configuration
func (h *Handler) ApplyConfig(c *gin.Context) {
	userID, _ := c.Get("user_id")

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

	// Run apply in background
	go func() {
		ctx := c.Request.Context()
		h.taskEngine.StartTask(ctx, taskID)
		h.taskEngine.UpdateProgress(ctx, taskID, 50, "Writing SCST configuration...")

		configPath := "/etc/calypso/scst/generated.conf"
		if err := h.service.WriteConfig(ctx, configPath); err != nil {
			h.taskEngine.FailTask(ctx, taskID, err.Error())
			return
		}

		h.taskEngine.UpdateProgress(ctx, taskID, 100, "SCST configuration applied")
		h.taskEngine.CompleteTask(ctx, taskID, "SCST configuration applied successfully")
	}()

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

// ListHandlers lists available SCST handlers
func (h *Handler) ListHandlers(c *gin.Context) {
	handlers, err := h.service.DetectHandlers(c.Request.Context())
	if err != nil {
		h.logger.Error("Failed to list handlers", "error", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list handlers"})
		return
	}

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

