package responses

import (
	"fmt"
	"time"

	"github.com/shopspring/decimal"

	"github.com/treytartt/honeydue-api/internal/models"
	"github.com/treytartt/honeydue-api/internal/task/categorization"
	"github.com/treytartt/honeydue-api/internal/task/predicates"
)

// TaskCategoryResponse represents a task category
type TaskCategoryResponse struct {
	ID           uint   `json:"id"`
	Name         string `json:"name"`
	Description  string `json:"description"`
	Icon         string `json:"icon"`
	Color        string `json:"color"`
	DisplayOrder int    `json:"display_order"`
}

// TaskPriorityResponse represents a task priority
type TaskPriorityResponse struct {
	ID           uint   `json:"id"`
	Name         string `json:"name"`
	Level        int    `json:"level"`
	Color        string `json:"color"`
	DisplayOrder int    `json:"display_order"`
}

// TaskFrequencyResponse represents a task frequency
type TaskFrequencyResponse struct {
	ID           uint   `json:"id"`
	Name         string `json:"name"`
	Days         *int   `json:"days"`
	DisplayOrder int    `json:"display_order"`
}

// TaskUserResponse represents a user in task context
type TaskUserResponse struct {
	ID        uint   `json:"id"`
	Username  string `json:"username"`
	Email     string `json:"email"`
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
}

// TaskCompletionImageResponse represents a completion image
type TaskCompletionImageResponse struct {
	ID       uint   `json:"id"`
	ImageURL string `json:"image_url"`
	MediaURL string `json:"media_url"` // Authenticated endpoint: /api/media/completion-image/{id}
	Caption  string `json:"caption"`
}

// TaskCompletionResponse represents a task completion
type TaskCompletionResponse struct {
	ID          uint                          `json:"id"`
	TaskID      uint                          `json:"task_id"`
	CompletedBy *TaskUserResponse             `json:"completed_by,omitempty"`
	CompletedAt time.Time                     `json:"completed_at"`
	Notes       string                        `json:"notes"`
	ActualCost  *decimal.Decimal              `json:"actual_cost"`
	Rating      *int                          `json:"rating"`
	Images      []TaskCompletionImageResponse `json:"images"`
	CreatedAt   time.Time                     `json:"created_at"`
	Task        *TaskResponse                 `json:"task,omitempty"` // Updated task after completion
}

// TaskResponse represents a task in the API response
type TaskResponse struct {
	ID              uint                     `json:"id"`
	ResidenceID     uint                     `json:"residence_id"`
	CreatedByID     uint                     `json:"created_by_id"`
	CreatedBy       *TaskUserResponse        `json:"created_by,omitempty"`
	AssignedToID    *uint                    `json:"assigned_to_id"`
	AssignedTo      *TaskUserResponse        `json:"assigned_to,omitempty"`
	Title           string                   `json:"title"`
	Description     string                   `json:"description"`
	CategoryID      *uint                    `json:"category_id"`
	Category        *TaskCategoryResponse    `json:"category,omitempty"`
	PriorityID      *uint                    `json:"priority_id"`
	Priority        *TaskPriorityResponse    `json:"priority,omitempty"`
	FrequencyID        *uint                    `json:"frequency_id"`
	Frequency          *TaskFrequencyResponse   `json:"frequency,omitempty"`
	CustomIntervalDays *int                     `json:"custom_interval_days"` // For "Custom" frequency, user-specified days
	InProgress         bool                     `json:"in_progress"`
	DueDate         *time.Time               `json:"due_date"`
	NextDueDate     *time.Time               `json:"next_due_date"` // For recurring tasks, updated after each completion
	EstimatedCost   *decimal.Decimal         `json:"estimated_cost"`
	ActualCost      *decimal.Decimal         `json:"actual_cost"`
	ContractorID    *uint                    `json:"contractor_id"`
	IsCancelled     bool                     `json:"is_cancelled"`
	IsArchived      bool                     `json:"is_archived"`
	ParentTaskID    *uint        `json:"parent_task_id"`
	TemplateID      *uint        `json:"template_id,omitempty"` // Backlink to the TaskTemplate this task was created from
	CompletionCount int          `json:"completion_count"`
	KanbanColumn    string       `json:"kanban_column,omitempty"` // Which kanban column this task belongs to
	CreatedAt       time.Time    `json:"created_at"`
	UpdatedAt       time.Time    `json:"updated_at"`
}

// BulkCreateTasksResponse is returned by POST /api/tasks/bulk/.
// All entries are created in a single transaction — if any insert fails the
// whole batch is rolled back and no partial state is visible.
type BulkCreateTasksResponse struct {
	Tasks        []TaskResponse `json:"tasks"`
	Summary      TotalSummary   `json:"summary"`
	CreatedCount int            `json:"created_count"`
}

// Note: Pagination removed - list endpoints now return arrays directly

// KanbanColumnResponse represents a kanban column
type KanbanColumnResponse struct {
	Name        string            `json:"name"`
	DisplayName string            `json:"display_name"`
	ButtonTypes []string          `json:"button_types"`
	Icons       map[string]string `json:"icons"`
	Color       string            `json:"color"`
	Tasks       []TaskResponse    `json:"tasks"`
	Count       int               `json:"count"`
}

// KanbanBoardResponse represents the kanban board
// NOTE: Summary statistics are calculated client-side from kanban data
type KanbanBoardResponse struct {
	Columns       []KanbanColumnResponse `json:"columns"`
	DaysThreshold int                    `json:"days_threshold"`
	ResidenceID   string                 `json:"residence_id"`
}

// Note: TaskCompletionListResponse pagination removed - returns arrays directly

// === Factory Functions ===

// NewTaskCategoryResponse creates a TaskCategoryResponse from a model
func NewTaskCategoryResponse(c *models.TaskCategory) *TaskCategoryResponse {
	if c == nil {
		return nil
	}
	return &TaskCategoryResponse{
		ID:           c.ID,
		Name:         c.Name,
		Description:  c.Description,
		Icon:         c.Icon,
		Color:        c.Color,
		DisplayOrder: c.DisplayOrder,
	}
}

// NewTaskPriorityResponse creates a TaskPriorityResponse from a model
func NewTaskPriorityResponse(p *models.TaskPriority) *TaskPriorityResponse {
	if p == nil {
		return nil
	}
	return &TaskPriorityResponse{
		ID:           p.ID,
		Name:         p.Name,
		Level:        p.Level,
		Color:        p.Color,
		DisplayOrder: p.DisplayOrder,
	}
}

// NewTaskFrequencyResponse creates a TaskFrequencyResponse from a model
func NewTaskFrequencyResponse(f *models.TaskFrequency) *TaskFrequencyResponse {
	if f == nil {
		return nil
	}
	return &TaskFrequencyResponse{
		ID:           f.ID,
		Name:         f.Name,
		Days:         f.Days,
		DisplayOrder: f.DisplayOrder,
	}
}

// NewTaskUserResponse creates a TaskUserResponse from a User model
func NewTaskUserResponse(u *models.User) *TaskUserResponse {
	if u == nil {
		return nil
	}
	return &TaskUserResponse{
		ID:        u.ID,
		Username:  u.Username,
		Email:     u.Email,
		FirstName: u.FirstName,
		LastName:  u.LastName,
	}
}

// NewTaskCompletionResponse creates a TaskCompletionResponse from a model
func NewTaskCompletionResponse(c *models.TaskCompletion) TaskCompletionResponse {
	resp := TaskCompletionResponse{
		ID:          c.ID,
		TaskID:      c.TaskID,
		CompletedAt: c.CompletedAt,
		Notes:       c.Notes,
		ActualCost:  c.ActualCost,
		Rating:      c.Rating,
		Images:      make([]TaskCompletionImageResponse, 0),
		CreatedAt:   c.CreatedAt,
	}
	if c.CompletedBy.ID != 0 {
		resp.CompletedBy = NewTaskUserResponse(&c.CompletedBy)
	}
	// Convert images with authenticated media URLs
	for _, img := range c.Images {
		resp.Images = append(resp.Images, TaskCompletionImageResponse{
			ID:       img.ID,
			ImageURL: img.ImageURL,
			MediaURL: fmt.Sprintf("/api/media/completion-image/%d", img.ID), // Authenticated endpoint
			Caption:  img.Caption,
		})
	}
	return resp
}

// NewTaskResponse creates a TaskResponse from a Task model
// Always includes kanban_column using default 30-day threshold
func NewTaskResponse(t *models.Task) TaskResponse {
	return NewTaskResponseWithThreshold(t, 30)
}

// NewTaskResponseWithThreshold creates a TaskResponse with a custom days threshold for kanban column.
// WARNING: Uses UTC time for kanban column. Prefer NewTaskResponseWithTime for timezone-aware responses.
func NewTaskResponseWithThreshold(t *models.Task, daysThreshold int) TaskResponse {
	return newTaskResponseInternal(t, daysThreshold, time.Now().UTC())
}

// NewTaskResponseWithTime creates a TaskResponse with timezone-aware kanban column categorization.
// The `now` parameter should be the start of day in the user's timezone.
func NewTaskResponseWithTime(t *models.Task, daysThreshold int, now time.Time) TaskResponse {
	return newTaskResponseInternal(t, daysThreshold, now)
}

// newTaskResponseInternal is the internal implementation for creating task responses
func newTaskResponseInternal(t *models.Task, daysThreshold int, now time.Time) TaskResponse {
	resp := TaskResponse{
		ID:              t.ID,
		ResidenceID:     t.ResidenceID,
		CreatedByID:     t.CreatedByID,
		Title:           t.Title,
		Description:     t.Description,
		CategoryID:      t.CategoryID,
		PriorityID:      t.PriorityID,
		FrequencyID:        t.FrequencyID,
		CustomIntervalDays: t.CustomIntervalDays,
		InProgress:         t.InProgress,
		AssignedToID:    t.AssignedToID,
		DueDate:         t.DueDate,
		NextDueDate:     t.NextDueDate,
		EstimatedCost:   t.EstimatedCost,
		ActualCost:      t.ActualCost,
		ContractorID:    t.ContractorID,
		IsCancelled:     t.IsCancelled,
		IsArchived:      t.IsArchived,
		ParentTaskID:    t.ParentTaskID,
		TemplateID:      t.TaskTemplateID,
		CompletionCount: predicates.GetCompletionCount(t),
		KanbanColumn:    DetermineKanbanColumnWithTime(t, daysThreshold, now),
		CreatedAt:       t.CreatedAt,
		UpdatedAt:       t.UpdatedAt,
	}

	if t.CreatedBy.ID != 0 {
		resp.CreatedBy = NewTaskUserResponse(&t.CreatedBy)
	}
	if t.AssignedTo != nil {
		resp.AssignedTo = NewTaskUserResponse(t.AssignedTo)
	}
	if t.Category != nil {
		resp.Category = NewTaskCategoryResponse(t.Category)
	}
	if t.Priority != nil {
		resp.Priority = NewTaskPriorityResponse(t.Priority)
	}
	if t.Frequency != nil {
		resp.Frequency = NewTaskFrequencyResponse(t.Frequency)
	}

	return resp
}

// NewTaskListResponse creates a list of task responses
func NewTaskListResponse(tasks []models.Task) []TaskResponse {
	results := make([]TaskResponse, len(tasks))
	for i, t := range tasks {
		results[i] = NewTaskResponse(&t)
	}
	return results
}

// NewKanbanBoardResponse creates a KanbanBoardResponse from a KanbanBoard model.
// The `now` parameter should be the start of day in the user's timezone so that
// individual task kanban columns are categorized consistently with the board query.
func NewKanbanBoardResponse(board *models.KanbanBoard, residenceID uint, now time.Time) KanbanBoardResponse {
	columns := make([]KanbanColumnResponse, len(board.Columns))
	for i, col := range board.Columns {
		tasks := make([]TaskResponse, len(col.Tasks))
		for j, t := range col.Tasks {
			tasks[j] = NewTaskResponseWithTime(&t, board.DaysThreshold, now)
		}
		columns[i] = KanbanColumnResponse{
			Name:        col.Name,
			DisplayName: col.DisplayName,
			ButtonTypes: col.ButtonTypes,
			Icons:       col.Icons,
			Color:       col.Color,
			Tasks:       tasks,
			Count:       col.Count,
		}
	}
	return KanbanBoardResponse{
		Columns:       columns,
		DaysThreshold: board.DaysThreshold,
		ResidenceID:   fmt.Sprintf("%d", residenceID),
	}
}

// NewKanbanBoardResponseForAll creates a KanbanBoardResponse for all residences (no specific residence ID).
// The `now` parameter should be the start of day in the user's timezone so that
// individual task kanban columns are categorized consistently with the board query.
func NewKanbanBoardResponseForAll(board *models.KanbanBoard, now time.Time) KanbanBoardResponse {
	columns := make([]KanbanColumnResponse, len(board.Columns))
	for i, col := range board.Columns {
		tasks := make([]TaskResponse, len(col.Tasks))
		for j, t := range col.Tasks {
			tasks[j] = NewTaskResponseWithTime(&t, board.DaysThreshold, now)
		}
		columns[i] = KanbanColumnResponse{
			Name:        col.Name,
			DisplayName: col.DisplayName,
			ButtonTypes: col.ButtonTypes,
			Icons:       col.Icons,
			Color:       col.Color,
			Tasks:       tasks,
			Count:       col.Count,
		}
	}
	return KanbanBoardResponse{
		Columns:       columns,
		DaysThreshold: board.DaysThreshold,
		ResidenceID:   "all",
	}
}

// NewTaskCompletionListResponse creates a list of task completion responses
func NewTaskCompletionListResponse(completions []models.TaskCompletion) []TaskCompletionResponse {
	results := make([]TaskCompletionResponse, len(completions))
	for i, c := range completions {
		results[i] = NewTaskCompletionResponse(&c)
	}
	return results
}

// NewTaskCompletionWithTaskResponse creates a TaskCompletionResponse with the updated task included.
// WARNING: Uses UTC time for kanban column. Prefer NewTaskCompletionWithTaskResponseWithTime for timezone-aware responses.
func NewTaskCompletionWithTaskResponse(c *models.TaskCompletion, task *models.Task, daysThreshold int) TaskCompletionResponse {
	return NewTaskCompletionWithTaskResponseWithTime(c, task, daysThreshold, time.Now().UTC())
}

// NewTaskCompletionWithTaskResponseWithTime creates a TaskCompletionResponse with timezone-aware kanban categorization.
// The `now` parameter should be the start of day in the user's timezone.
func NewTaskCompletionWithTaskResponseWithTime(c *models.TaskCompletion, task *models.Task, daysThreshold int, now time.Time) TaskCompletionResponse {
	resp := NewTaskCompletionResponse(c)

	if task != nil {
		taskResp := NewTaskResponseWithTime(task, daysThreshold, now)
		resp.Task = &taskResp
	}

	return resp
}

// DetermineKanbanColumn determines which kanban column a task belongs to.
// Delegates to internal/task/categorization package which is the single source
// of truth for task categorization logic.
//
// WARNING: This uses UTC time which may cause incorrect categorization when
// server time is past midnight UTC but user's local time is still the previous day.
// Prefer DetermineKanbanColumnWithTime for timezone-aware categorization.
func DetermineKanbanColumn(task *models.Task, daysThreshold int) string {
	return categorization.DetermineKanbanColumn(task, daysThreshold)
}

// DetermineKanbanColumnWithTime determines which kanban column a task belongs to
// using a specific time (should be start of day in user's timezone).
func DetermineKanbanColumnWithTime(task *models.Task, daysThreshold int, now time.Time) string {
	return categorization.DetermineKanbanColumnWithTime(task, daysThreshold, now)
}

// === Response Wrappers with Summary ===
// These wrap CRUD responses with TotalSummary to eliminate extra API calls

// TaskWithSummaryResponse wraps TaskResponse with TotalSummary
type TaskWithSummaryResponse struct {
	Data    TaskResponse `json:"data"`
	Summary TotalSummary `json:"summary"`
}

// TaskCompletionWithSummaryResponse wraps TaskCompletionResponse with TotalSummary
type TaskCompletionWithSummaryResponse struct {
	Data    TaskCompletionResponse `json:"data"`
	Summary TotalSummary           `json:"summary"`
}

// DeleteWithSummaryResponse for delete operations
type DeleteWithSummaryResponse struct {
	Data    string       `json:"data"`
	Summary TotalSummary `json:"summary"`
}
