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

// Package habits provides MCP tools for habit tracking in Lunatask.
package habits

import (
	"context"
	"encoding/json"
	"fmt"

	"git.secluded.site/go-lunatask"
	"github.com/modelcontextprotocol/go-sdk/mcp"

	"git.secluded.site/lunatask-mcp-server/tools/shared"
)

// Handler handles habit-related MCP tool calls.
type Handler struct {
	client *lunatask.Client
	habits []shared.HabitProvider
}

// NewHandler creates a new habits Handler for tool operations.
func NewHandler(accessToken string, habits []shared.HabitProvider) *Handler {
	return &Handler{
		client: lunatask.NewClient(accessToken),
		habits: habits,
	}
}

// ResourceHandler handles habit-related MCP resource requests.
type ResourceHandler struct {
	habits []shared.HabitProvider
}

// NewResourceHandler creates a new habits ResourceHandler for resource reads.
func NewResourceHandler(habits []shared.HabitProvider) *ResourceHandler {
	return &ResourceHandler{habits: habits}
}

// HandleTrack handles the track_habit_activity tool call.
func (h *Handler) HandleTrack(
	ctx context.Context,
	_ *mcp.CallToolRequest,
	input TrackInput,
) (*mcp.CallToolResult, TrackOutput, error) {
	// Resolve habit by ID or key
	habit := shared.FindHabit(h.habits, input.HabitID)
	if habit == nil {
		return nil, TrackOutput{}, fmt.Errorf("habit not found: %s", input.HabitID)
	}

	performedOn, err := lunatask.ParseDate(input.PerformedOn)
	if err != nil {
		return nil, TrackOutput{}, fmt.Errorf(
			"invalid format for performed_on %q: must be YYYY-MM-DD",
			input.PerformedOn,
		)
	}

	resp, err := h.client.TrackHabitActivity(ctx, habit.GetID(), &lunatask.TrackHabitActivityRequest{
		PerformedOn: performedOn,
	})
	if err != nil {
		return nil, TrackOutput{}, fmt.Errorf("failed to track habit activity: %w", err)
	}

	return nil, TrackOutput{
		Status:  resp.Status,
		Message: resp.Message,
	}, nil
}

// ResourceURI is the URI for the habits resource.
const ResourceURI = "lunatask://habits"

// HabitInfo represents a habit for JSON serialization.
type HabitInfo struct {
	Key  string `json:"key"`
	Name string `json:"name"`
	ID   string `json:"id"`
}

// HandleRead handles the habits resource read request.
func (h *ResourceHandler) HandleRead(
	_ context.Context,
	_ *mcp.ReadResourceRequest,
) (*mcp.ReadResourceResult, error) {
	habitsInfo := make([]HabitInfo, 0, len(h.habits))

	for _, habit := range h.habits {
		habitsInfo = append(habitsInfo, HabitInfo{
			Key:  habit.GetKey(),
			Name: habit.GetName(),
			ID:   habit.GetID(),
		})
	}

	data, err := json.MarshalIndent(habitsInfo, "", "  ")
	if err != nil {
		return nil, err
	}

	return &mcp.ReadResourceResult{
		Contents: []*mcp.ResourceContents{{
			URI:      ResourceURI,
			MIMEType: "application/json",
			Text:     string(data),
		}},
	}, nil
}
