// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

// Package task provides MCP tools for Lunatask task operations.
package task

import (
	"context"

	"git.secluded.site/go-lunatask"
	"git.secluded.site/lune/internal/config"
	"git.secluded.site/lune/internal/dateutil"
	"git.secluded.site/lune/internal/mcp/shared"
	"git.secluded.site/lune/internal/validate"
	"github.com/modelcontextprotocol/go-sdk/mcp"
)

// CreateToolName is the name of the create task tool.
const CreateToolName = "create_task"

// CreateToolDescription describes the create task tool for LLMs.
const CreateToolDescription = `Creates a new task in Lunatask.

Required:
- name: Task title

Optional:
- area_id: Area UUID, lunatask:// deep link, or config key
- goal_id: Goal UUID, lunatask:// deep link, or config key (requires area_id)
- status: later, next, started, waiting (default: later)
- note: Markdown note/description for the task
- priority: lowest, low, normal, high, highest
- estimate: Time estimate in minutes (0-720)
- motivation: must, should, want
- important: true/false for Eisenhower matrix
- urgent: true/false for Eisenhower matrix
- scheduled_on: Date to schedule (YYYY-MM-DD or natural language)

Returns the created task's ID and deep link.`

// CreateInput is the input schema for creating a task.
type CreateInput struct {
	Name        string  `json:"name"                   jsonschema:"required"`
	AreaID      *string `json:"area_id,omitempty"`
	GoalID      *string `json:"goal_id,omitempty"`
	Status      *string `json:"status,omitempty"`
	Note        *string `json:"note,omitempty"`
	Priority    *string `json:"priority,omitempty"`
	Estimate    *int    `json:"estimate,omitempty"`
	Motivation  *string `json:"motivation,omitempty"`
	Important   *bool   `json:"important,omitempty"`
	Urgent      *bool   `json:"urgent,omitempty"`
	ScheduledOn *string `json:"scheduled_on,omitempty"`
}

// CreateOutput is the output schema for creating a task.
type CreateOutput struct {
	DeepLink string `json:"deep_link"`
}

// parsedCreateInput holds validated and parsed create input fields.
type parsedCreateInput struct {
	Name        string
	AreaID      *string
	GoalID      *string
	Status      *lunatask.TaskStatus
	Note        *string
	Priority    *lunatask.Priority
	Estimate    *int
	Motivation  *lunatask.Motivation
	Important   *bool
	Urgent      *bool
	ScheduledOn *lunatask.Date
}

// Handler handles task-related MCP tool requests.
type Handler struct {
	client *lunatask.Client
	cfg    *config.Config
	areas  []shared.AreaProvider
}

// NewHandler creates a new task handler.
func NewHandler(accessToken string, cfg *config.Config, areas []shared.AreaProvider) *Handler {
	return &Handler{
		client: lunatask.NewClient(accessToken, lunatask.UserAgent("lune-mcp/1.0")),
		cfg:    cfg,
		areas:  areas,
	}
}

// HandleCreate creates a new task.
func (h *Handler) HandleCreate(
	ctx context.Context,
	_ *mcp.CallToolRequest,
	input CreateInput,
) (*mcp.CallToolResult, CreateOutput, error) {
	parsed, errResult := parseCreateInput(h.cfg, input)
	if errResult != nil {
		return errResult, CreateOutput{}, nil
	}

	builder := h.client.NewTask(parsed.Name)
	applyToTaskBuilder(builder, parsed)

	task, err := builder.Create(ctx)
	if err != nil {
		return shared.ErrorResult(err.Error()), CreateOutput{}, nil
	}

	deepLink, _ := lunatask.BuildDeepLink(lunatask.ResourceTask, task.ID)

	return &mcp.CallToolResult{
		Content: []mcp.Content{&mcp.TextContent{
			Text: "Task created: " + deepLink,
		}},
	}, CreateOutput{DeepLink: deepLink}, nil
}

//nolint:cyclop,funlen
func parseCreateInput(cfg *config.Config, input CreateInput) (*parsedCreateInput, *mcp.CallToolResult) {
	parsed := &parsedCreateInput{
		Name:      input.Name,
		Note:      input.Note,
		Estimate:  input.Estimate,
		Important: input.Important,
		Urgent:    input.Urgent,
	}

	if input.AreaID != nil {
		areaID, err := validate.AreaRef(cfg, *input.AreaID)
		if err != nil {
			return nil, shared.ErrorResult(err.Error())
		}

		parsed.AreaID = &areaID
	}

	if input.GoalID != nil {
		areaID := ""
		if parsed.AreaID != nil {
			areaID = *parsed.AreaID
		}

		goalID, err := validate.GoalRef(cfg, areaID, *input.GoalID)
		if err != nil {
			return nil, shared.ErrorResult(err.Error())
		}

		parsed.GoalID = &goalID
	}

	if input.Estimate != nil {
		if err := shared.ValidateEstimate(*input.Estimate); err != nil {
			return nil, shared.ErrorResult(err.Error())
		}
	}

	if input.Status != nil {
		status, err := lunatask.ParseTaskStatus(*input.Status)
		if err != nil {
			return nil, shared.ErrorResult(err.Error())
		}

		parsed.Status = &status
	}

	if input.Priority != nil {
		priority, err := lunatask.ParsePriority(*input.Priority)
		if err != nil {
			return nil, shared.ErrorResult(err.Error())
		}

		parsed.Priority = &priority
	}

	if input.Motivation != nil {
		motivation, err := lunatask.ParseMotivation(*input.Motivation)
		if err != nil {
			return nil, shared.ErrorResult(err.Error())
		}

		parsed.Motivation = &motivation
	}

	if input.ScheduledOn != nil {
		date, err := dateutil.Parse(*input.ScheduledOn)
		if err != nil {
			return nil, shared.ErrorResult(err.Error())
		}

		parsed.ScheduledOn = &date
	}

	return parsed, nil
}

//nolint:cyclop
func applyToTaskBuilder(builder *lunatask.TaskBuilder, parsed *parsedCreateInput) {
	if parsed.AreaID != nil {
		builder.InArea(*parsed.AreaID)
	}

	if parsed.GoalID != nil {
		builder.InGoal(*parsed.GoalID)
	}

	if parsed.Status != nil {
		builder.WithStatus(*parsed.Status)
	}

	if parsed.Note != nil {
		builder.WithNote(*parsed.Note)
	}

	if parsed.Priority != nil {
		builder.Priority(*parsed.Priority)
	}

	if parsed.Estimate != nil {
		builder.WithEstimate(*parsed.Estimate)
	}

	if parsed.Motivation != nil {
		builder.WithMotivation(*parsed.Motivation)
	}

	if parsed.Important != nil {
		if *parsed.Important {
			builder.Important()
		} else {
			builder.NotImportant()
		}
	}

	if parsed.Urgent != nil {
		if *parsed.Urgent {
			builder.Urgent()
		} else {
			builder.NotUrgent()
		}
	}

	if parsed.ScheduledOn != nil {
		builder.ScheduledOn(*parsed.ScheduledOn)
	}
}
