package handler

import (
	"net/http"
	"strconv"

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

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

// ProjectHandler handles project CRUD endpoints.
type ProjectHandler struct {
	Svc *service.ProjectService
}

func NewProjectHandler(svc *service.ProjectService) *ProjectHandler {
	return &ProjectHandler{Svc: svc}
}

// ListProjects returns all projects.
func (h *ProjectHandler) ListProjects(c *gin.Context) {
	projects, err := h.Svc.ListProjects()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if projects == nil {
		projects = []model.Project{}
	}
	c.JSON(http.StatusOK, projects)
}

// GetProject returns a single project by ID.
func (h *ProjectHandler) GetProject(c *gin.Context) {
	id, err := parseID(c)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"})
		return
	}
	project, err := h.Svc.GetProject(id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "project not found"})
		return
	}
	c.JSON(http.StatusOK, project)
}

// CreateProject creates a new project.
func (h *ProjectHandler) CreateProject(c *gin.Context) {
	var p model.Project
	if err := c.ShouldBindJSON(&p); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if p.Name == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "name is required"})
		return
	}
	if p.Mode != "git" && p.Mode != "upload" {
		p.Mode = "git" // default
	}
	if err := h.Svc.CreateProject(&p); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusCreated, p)
}

// UpdateProject updates an existing project.
func (h *ProjectHandler) UpdateProject(c *gin.Context) {
	id, err := parseID(c)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"})
		return
	}

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

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

	// Preserve fields that should not be updated from the request
	updates.ID = existing.ID
	updates.CreatedAt = existing.CreatedAt
	updates.Status = existing.Status
	updates.PID = existing.PID
	// Preserve password if not sent
	if updates.GitPassword == "" {
		updates.GitPassword = existing.GitPassword
	}

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

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

func parseID(c *gin.Context) (uint, error) {
	idStr := c.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		return 0, err
	}
	return uint(id), nil
}
