package api

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

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

type CreateTaskRequest struct {
	Title        string `json:"title" binding:"required"`
	Description  string `json:"description"`
	Priority     string `json:"priority"`
	DueDate      string `json:"due_date"`
	AssignedToID *uint  `json:"assigned_to_id"`
}

type UpdateTaskRequest struct {
	Title        string `json:"title"`
	Description  string `json:"description"`
	Status       string `json:"status"`
	Priority     string `json:"priority"`
	DueDate      string `json:"due_date"`
	AssignedToID *uint  `json:"assigned_to_id"`
	Position     *int   `json:"position"`
}

type CreateSubtaskRequest struct {
	Title        string `json:"title" binding:"required"`
	Description  string `json:"description"`
	AssignedToID *uint  `json:"assigned_to_id"`
}

type CreateCommentRequest struct {
	Content string `json:"content" binding:"required"`
}

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

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

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

	task := models.Task{
		Title:        req.Title,
		Description:  req.Description,
		Priority:     req.Priority,
		ProjectID:    projectObj.ID,
		CreatedByID:  userObj.ID,
		AssignedToID: req.AssignedToID,
		Status:       "todo",
	}

	if task.Priority == "" {
		task.Priority = "medium"
	}

	// Parse due date if provided
	if req.DueDate != "" {
		if dueDate, err := time.Parse("2006-01-02T15:04:05Z07:00", req.DueDate); err == nil {
			task.DueDate = &dueDate
		}
	}

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

	// Load task with relationships
	models.GetDB().
		Preload("Project").
		Preload("AssignedTo").
		Preload("CreatedBy").
		First(&task, task.ID)

	utils.SuccessResponse(c, http.StatusCreated, "Task created successfully", task)
}

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

	projectObj := project.(*models.Project)

	var tasks []models.Task

	if err := models.GetDB().
		Preload("AssignedTo").
		Preload("CreatedBy").
		Preload("Comments").
		Preload("Files").
		Preload("Subtasks").
		Preload("Labels").
		Where("project_id = ?", projectObj.ID).
		Order("position ASC, created_at DESC").
		Find(&tasks).Error; err != nil {
		utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to fetch tasks")
		return
	}

	utils.SuccessResponse(c, http.StatusOK, "Tasks retrieved successfully", tasks)
}

// GetTask returns a specific task
func GetTask(c *gin.Context) {
	project, _ := c.Get("project")
	projectObj := project.(*models.Project)

	taskID := c.Param("task_id")
	if taskID == "" {
		utils.ErrorResponse(c, http.StatusBadRequest, "Task ID required")
		return
	}

	var task models.Task
	if err := models.GetDB().
		Preload("Project").
		Preload("AssignedTo").
		Preload("CreatedBy").
		Preload("Comments").
		Preload("Comments.User").
		Preload("Files").
		Preload("Subtasks").
		Preload("Subtasks.AssignedTo").
		Preload("Labels").
		Where("id = ? AND project_id = ?", taskID, projectObj.ID).
		First(&task).Error; err != nil {
		utils.ErrorResponse(c, http.StatusNotFound, "Task not found")
		return
	}

	utils.SuccessResponse(c, http.StatusOK, "Task retrieved successfully", task)
}

// UpdateTask updates a task
func UpdateTask(c *gin.Context) {
	project, _ := c.Get("project")
	projectObj := project.(*models.Project)

	taskID := c.Param("task_id")
	if taskID == "" {
		utils.ErrorResponse(c, http.StatusBadRequest, "Task ID required")
		return
	}

	var task models.Task
	if err := models.GetDB().
		Where("id = ? AND project_id = ?", taskID, projectObj.ID).
		First(&task).Error; err != nil {
		utils.ErrorResponse(c, http.StatusNotFound, "Task not found")
		return
	}

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

	// Update fields
	if req.Title != "" {
		task.Title = req.Title
	}
	if req.Description != "" {
		task.Description = req.Description
	}
	if req.Status != "" {
		task.Status = req.Status
		if req.Status == "done" {
			task.MarkAsCompleted()
		}
	}
	if req.Priority != "" {
		task.Priority = req.Priority
	}
	if req.AssignedToID != nil {
		task.AssignedToID = req.AssignedToID
	}
	if req.Position != nil {
		task.Position = *req.Position
	}

	// Parse due date if provided
	if req.DueDate != "" {
		if dueDate, err := time.Parse("2006-01-02T15:04:05Z07:00", req.DueDate); err == nil {
			task.DueDate = &dueDate
		}
	}

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

	// Load updated task with relationships
	models.GetDB().
		Preload("AssignedTo").
		Preload("CreatedBy").
		Preload("Comments").
		Preload("Files").
		Preload("Subtasks").
		Preload("Labels").
		First(&task, task.ID)

	utils.SuccessResponse(c, http.StatusOK, "Task updated successfully", task)
}

// DeleteTask deletes a task
func DeleteTask(c *gin.Context) {
	project, _ := c.Get("project")
	projectObj := project.(*models.Project)

	taskID := c.Param("task_id")
	if taskID == "" {
		utils.ErrorResponse(c, http.StatusBadRequest, "Task ID required")
		return
	}

	var task models.Task
	if err := models.GetDB().
		Where("id = ? AND project_id = ?", taskID, projectObj.ID).
		First(&task).Error; err != nil {
		utils.ErrorResponse(c, http.StatusNotFound, "Task not found")
		return
	}

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

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

// CreateSubtask creates a new subtask
func CreateSubtask(c *gin.Context) {
	project, _ := c.Get("project")
	projectObj := project.(*models.Project)

	taskID := c.Param("task_id")
	if taskID == "" {
		utils.ErrorResponse(c, http.StatusBadRequest, "Task ID required")
		return
	}

	// Verify task exists and belongs to project
	var task models.Task
	if err := models.GetDB().
		Where("id = ? AND project_id = ?", taskID, projectObj.ID).
		First(&task).Error; err != nil {
		utils.ErrorResponse(c, http.StatusNotFound, "Task not found")
		return
	}

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

	subtask := models.Subtask{
		Title:        req.Title,
		Description:  req.Description,
		ParentTaskID: task.ID,
		AssignedToID: req.AssignedToID,
		Status:       "todo",
	}

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

	// Load subtask with relationships
	models.GetDB().
		Preload("AssignedTo").
		First(&subtask, subtask.ID)

	utils.SuccessResponse(c, http.StatusCreated, "Subtask created successfully", subtask)
}

// AddComment adds a comment to a task
func AddComment(c *gin.Context) {
	user, exists := c.Get("user")
	if !exists {
		utils.ErrorResponse(c, http.StatusUnauthorized, "User not authenticated")
		return
	}

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

	taskID := c.Param("task_id")
	if taskID == "" {
		utils.ErrorResponse(c, http.StatusBadRequest, "Task ID required")
		return
	}

	// Verify task exists and belongs to project
	var task models.Task
	if err := models.GetDB().
		Where("id = ? AND project_id = ?", taskID, projectObj.ID).
		First(&task).Error; err != nil {
		utils.ErrorResponse(c, http.StatusNotFound, "Task not found")
		return
	}

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

	comment := models.Comment{
		Content: req.Content,
		TaskID:  task.ID,
		UserID:  userObj.ID,
	}

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

	// Load comment with user
	models.GetDB().
		Preload("User").
		First(&comment, comment.ID)

	utils.SuccessResponse(c, http.StatusCreated, "Comment added successfully", comment)
}
