package handler

import (
	"context"
	"net/http"
	"strconv"
	"time"

	"ci/internal/model"
	"ci/internal/service"

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

// DeployHandler handles deployment endpoints.
type DeployHandler struct {
	Svc *service.ProjectService
}

// NewDeployHandler creates a new DeployHandler.
func NewDeployHandler(svc *service.ProjectService) *DeployHandler {
	return &DeployHandler{Svc: svc}
}

// GetDeployConfig returns the deploy config for a project.
func (h *DeployHandler) GetDeployConfig(c *gin.Context) {
	id, err := parseID(c)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"})
		return
	}

	cfg, err := h.Svc.GetDeployConfig(id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if cfg == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "no deploy config"})
		return
	}
	c.JSON(http.StatusOK, cfg)
}

// UpdateDeployConfig creates or updates the deploy config for a project.
func (h *DeployHandler) UpdateDeployConfig(c *gin.Context) {
	id, err := parseID(c)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"})
		return
	}

	var cfg model.DeployConfig
	if err := c.ShouldBindJSON(&cfg); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	cfg.ProjectID = id

	if err := h.Svc.UpdateDeployConfig(&cfg); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Re-fetch to return clean state (sensitive fields hidden by json:"-")
	result, _ := h.Svc.GetDeployConfig(id)
	if result == nil {
		c.JSON(http.StatusOK, gin.H{"message": "created"})
		return
	}
	c.JSON(http.StatusOK, result)
}

// DeleteDeployConfig removes the deploy config for a project.
func (h *DeployHandler) DeleteDeployConfig(c *gin.Context) {
	id, err := parseID(c)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"})
		return
	}

	if err := h.Svc.DeleteDeployConfig(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "deploy config deleted"})
}

// TriggerDeploy starts a deployment for the project.
func (h *DeployHandler) TriggerDeploy(c *gin.Context) {
	id, err := parseID(c)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"})
		return
	}

	// Deploy in background
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
	defer cancel()

	go func() {
		h.Svc.TriggerDeploy(ctx, id, nil)
	}()

	c.JSON(http.StatusAccepted, gin.H{"message": "deployment started"})
}

// GetDeployRecords lists deploy history for a project.
func (h *DeployHandler) GetDeployRecords(c *gin.Context) {
	id, err := parseID(c)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"})
		return
	}

	records, err := h.Svc.GetDeployHistory(id, 50)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if records == nil {
		records = []model.DeployRecord{}
	}
	c.JSON(http.StatusOK, records)
}

// GetDeployLog returns the full log for a specific deployment.
func (h *DeployHandler) GetDeployLog(c *gin.Context) {
	didStr := c.Param("did")
	did, err := parseIDStr(didStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid deploy id"})
		return
	}

	logContent, err := h.Svc.GetDeployLog(did)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.String(http.StatusOK, logContent)
}

// parseIDStr parses an ID string for non-param-based IDs (e.g., deploy record ID from URL path).
func parseIDStr(s string) (uint, error) {
	id, err := strconv.ParseUint(s, 10, 64)
	if err != nil {
		return 0, err
	}
	return uint(id), nil
}
