package handler

import (
	"fmt"
	"io"
	"net/http"
	"time"

	"context"

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

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

// BuildHandler handles build/run/log endpoints.
type BuildHandler struct {
	Svc *service.ProjectService
}

func NewBuildHandler(svc *service.ProjectService) *BuildHandler {
	return &BuildHandler{Svc: svc}
}

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

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

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

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

// StartProject starts the project's binary.
func (h *BuildHandler) StartProject(c *gin.Context) {
	id, err := parseID(c)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"})
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

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

// StopProject stops a running project.
func (h *BuildHandler) StopProject(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.StopProject(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "stopped"})
}

// RestartProject restarts a project.
func (h *BuildHandler) RestartProject(c *gin.Context) {
	id, err := parseID(c)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"})
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

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

// GetBuilds lists build history for a project.
func (h *BuildHandler) GetBuilds(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.GetBuildHistory(id, 50)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if records == nil {
		records = []model.BuildRecord{}
	}
	c.JSON(http.StatusOK, records)
}

// GetBuildLog returns the full log for a specific build.
func (h *BuildHandler) GetBuildLog(c *gin.Context) {
	id, err := parseID(c)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid build id"})
		return
	}

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

// StreamLogs streams real-time logs via SSE for a project.
func (h *BuildHandler) StreamLogs(c *gin.Context) {
	id, err := parseID(c)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"})
		return
	}

	c.Header("Content-Type", "text/event-stream")
	c.Header("Cache-Control", "no-cache")
	c.Header("Connection", "keep-alive")
	c.Header("Access-Control-Allow-Origin", "*")

	ch := h.Svc.SubscribeLogs(id)
	defer h.Svc.UnsubscribeLogs(id, ch)

	clientGone := c.Request.Context().Done()

	c.Stream(func(w io.Writer) bool {
		select {
		case <-clientGone:
			return false
		case line, ok := <-ch:
			if !ok {
				return false
			}
			fmt.Fprintf(w, "data: %s\n\n", line)
			return true
		}
	})
}

// Webhook handles Git webhook triggers (Gitee/GitHub).
func (h *BuildHandler) Webhook(c *gin.Context) {
	id, err := parseID(c)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"})
		return
	}

	// Verify project exists
	_, err = h.Svc.GetProject(id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "project not found"})
		return
	}

	// Trigger build
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute)
	defer cancel()

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

	c.JSON(http.StatusOK, gin.H{"message": "webhook received, build triggered"})
}
