package api

import (
	"net/http"
	"project-dashboard/api/utils"
	"project-dashboard/models"
	"strconv"

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

type CreateProjectRequest struct {
	Name        string `json:"name" binding:"required"`
	Description string `json:"description"`
	Color       string `json:"color"`
}

type UpdateProjectRequest struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Status      string `json:"status"`
	Color       string `json:"color"`
}

type AddMemberRequest struct {
	UserID uint   `json:"user_id" binding:"required"`
	Role   string `json:"role"`
}

// CreateProject creates a new project
func CreateProject(c *gin.Context) {
	user, exists := c.Get("user")
	if !exists {
		utils.ErrorResponse(c, http.StatusUnauthorized, "User not authenticated")
		return
	}

	userObj := user.(*models.User)

	var req CreateProjectRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		utils.ValidationErrorResponse(c, gin.H{
			"error": err.Error(),
		})
		return
	}

	project := models.Project{
		Name:        req.Name,
		Description: req.Description,
		Color:       req.Color,
		OwnerID:     userObj.ID,
		Status:      "active",
	}

	if project.Color == "" {
		project.Color = "#3b82f6"
	}

	if err := models.GetDB().Create(&project).Error; err != nil {
		utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to create project")
		return
	}

	// Add owner as project member
	member := models.ProjectMember{
		ProjectID: project.ID,
		UserID:    userObj.ID,
		Role:      "owner",
	}
	models.GetDB().Create(&member)

	// Load project with relationships
	models.GetDB().Preload("Owner").Preload("Members").First(&project, project.ID)

	utils.SuccessResponse(c, http.StatusCreated, "Project created successfully", project)
}

// GetProjects returns all projects for the current user
func GetProjects(c *gin.Context) {
	user, exists := c.Get("user")
	if !exists {
		utils.ErrorResponse(c, http.StatusUnauthorized, "User not authenticated")
		return
	}

	userObj := user.(*models.User)

	var projects []models.Project

	// Get projects where user is owner or member
	if err := models.GetDB().
		Preload("Owner").
		Preload("Members").
		Where("owner_id = ? OR id IN (SELECT project_id FROM project_members WHERE user_id = ?)",
			userObj.ID, userObj.ID).
		Find(&projects).Error; err != nil {
		utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to fetch projects")
		return
	}

	utils.SuccessResponse(c, http.StatusOK, "Projects retrieved successfully", projects)
}

// GetProject returns a specific project
func GetProject(c *gin.Context) {
	project, exists := c.Get("project")
	if !exists {
		utils.ErrorResponse(c, http.StatusNotFound, "Project not found")
		return
	}

	projectObj := project.(*models.Project)

	// Load additional relationships
	models.GetDB().
		Preload("Owner").
		Preload("Members").
		Preload("Tasks").
		Preload("Files").
		First(projectObj, projectObj.ID)

	utils.SuccessResponse(c, http.StatusOK, "Project retrieved successfully", projectObj)
}

// UpdateProject updates a project
func UpdateProject(c *gin.Context) {
	project, exists := c.Get("project")
	if !exists {
		utils.ErrorResponse(c, http.StatusNotFound, "Project not found")
		return
	}

	projectObj := project.(*models.Project)
	user, _ := c.Get("user")
	userObj := user.(*models.User)

	// Check if user is owner or manager
	role := projectObj.GetMemberRole(userObj.ID)
	if role != "owner" && role != "manager" {
		utils.ErrorResponse(c, http.StatusForbidden, "Insufficient permissions")
		return
	}

	var req UpdateProjectRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		utils.ValidationErrorResponse(c, gin.H{
			"error": err.Error(),
		})
		return
	}

	// Update fields
	if req.Name != "" {
		projectObj.Name = req.Name
	}
	if req.Description != "" {
		projectObj.Description = req.Description
	}
	if req.Status != "" {
		projectObj.Status = req.Status
	}
	if req.Color != "" {
		projectObj.Color = req.Color
	}

	if err := models.GetDB().Save(projectObj).Error; err != nil {
		utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to update project")
		return
	}

	utils.SuccessResponse(c, http.StatusOK, "Project updated successfully", projectObj)
}

// DeleteProject deletes a project
func DeleteProject(c *gin.Context) {
	project, exists := c.Get("project")
	if !exists {
		utils.ErrorResponse(c, http.StatusNotFound, "Project not found")
		return
	}

	projectObj := project.(*models.Project)
	user, _ := c.Get("user")
	userObj := user.(*models.User)

	// Only owner can delete project
	if !projectObj.IsOwner(userObj.ID) {
		utils.ErrorResponse(c, http.StatusForbidden, "Only project owner can delete project")
		return
	}

	if err := models.GetDB().Delete(projectObj).Error; err != nil {
		utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to delete project")
		return
	}

	utils.SuccessResponse(c, http.StatusOK, "Project deleted successfully", nil)
}

// AddMember adds a member to the project
func AddMember(c *gin.Context) {
	project, exists := c.Get("project")
	if !exists {
		utils.ErrorResponse(c, http.StatusNotFound, "Project not found")
		return
	}

	projectObj := project.(*models.Project)
	user, _ := c.Get("user")
	userObj := user.(*models.User)

	// Check if user has permission to add members
	role := projectObj.GetMemberRole(userObj.ID)
	if role != "owner" && role != "manager" {
		utils.ErrorResponse(c, http.StatusForbidden, "Insufficient permissions")
		return
	}

	var req AddMemberRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		utils.ValidationErrorResponse(c, gin.H{
			"error": err.Error(),
		})
		return
	}

	// Check if user exists
	var targetUser models.User
	if err := models.GetDB().First(&targetUser, req.UserID).Error; err != nil {
		utils.ErrorResponse(c, http.StatusNotFound, "User not found")
		return
	}

	// Check if user is already a member
	if projectObj.HasMember(req.UserID) {
		utils.ErrorResponse(c, http.StatusConflict, "User is already a member of this project")
		return
	}

	// Set default role
	if req.Role == "" {
		req.Role = "member"
	}

	member := models.ProjectMember{
		ProjectID: projectObj.ID,
		UserID:    req.UserID,
		Role:      req.Role,
	}

	if err := models.GetDB().Create(&member).Error; err != nil {
		utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to add member")
		return
	}

	// Load updated project
	models.GetDB().Preload("Members").First(projectObj, projectObj.ID)

	utils.SuccessResponse(c, http.StatusOK, "Member added successfully", projectObj)
}

// RemoveMember removes a member from the project
func RemoveMember(c *gin.Context) {
	project, exists := c.Get("project")
	if !exists {
		utils.ErrorResponse(c, http.StatusNotFound, "Project not found")
		return
	}

	projectObj := project.(*models.Project)
	user, _ := c.Get("user")
	userObj := user.(*models.User)

	// Check if user has permission to remove members
	role := projectObj.GetMemberRole(userObj.ID)
	if role != "owner" && role != "manager" {
		utils.ErrorResponse(c, http.StatusForbidden, "Insufficient permissions")
		return
	}

	userIDStr := c.Param("user_id")
	if userIDStr == "" {
		utils.ErrorResponse(c, http.StatusBadRequest, "User ID required")
		return
	}

	userID, err := strconv.ParseUint(userIDStr, 10, 32)
	if err != nil {
		utils.ErrorResponse(c, http.StatusBadRequest, "Invalid user ID")
		return
	}

	// Check if user is a member
	if !projectObj.HasMember(uint(userID)) {
		utils.ErrorResponse(c, http.StatusNotFound, "User is not a member of this project")
		return
	}

	// Remove member
	if err := models.GetDB().
		Where("project_id = ? AND user_id = ?", projectObj.ID, uint(userID)).
		Delete(&models.ProjectMember{}).Error; err != nil {
		utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to remove member")
		return
	}

	// Load updated project
	models.GetDB().Preload("Members").First(projectObj, projectObj.ID)

	utils.SuccessResponse(c, http.StatusOK, "Member removed successfully", projectObj)
}
