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

package tools

import (
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/ijt/go-anytime"
	"github.com/mark3labs/mcp-go/mcp"
)

// GetTimestampArgs defines the arguments for get_timestamp tool call.
type GetTimestampArgs struct {
	NaturalLanguageDate string `json:"natural_language_date"`
}

// AreaProvider defines the interface for accessing area data.
type AreaProvider interface {
	GetName() string
	GetID() string
	GetGoals() []GoalProvider
}

// GoalProvider defines the interface for accessing goal data.
type GoalProvider interface {
	GetName() string
	GetID() string
}

// HabitProvider defines the interface for accessing habit data.
type HabitProvider interface {
	GetName() string
	GetID() string
}

// HandlerConfig holds the necessary configuration for tool handlers.
type HandlerConfig struct {
	AccessToken string
	Timezone    string
	Areas       []AreaProvider
	Habits      []HabitProvider
}

// Handlers provides methods for handling MCP tool calls.
type Handlers struct {
	config HandlerConfig
}

// NewHandlers creates a new Handlers instance.
func NewHandlers(config HandlerConfig) *Handlers {
	return &Handlers{config: config}
}

// reportMCPError creates an MCP error result.
func reportMCPError(msg string) (*mcp.CallToolResult, error) {
	return &mcp.CallToolResult{
		IsError: true,
		Content: []mcp.Content{mcp.TextContent{Type: "text", Text: msg}},
	}, nil
}

// LoadLocation loads a timezone location string, returning a *time.Location or error
func LoadLocation(timezone string) (*time.Location, error) {
	if timezone == "" {
		return nil, fmt.Errorf("timezone is not configured; please set the 'timezone' value in your config file (e.g. 'UTC' or 'America/New_York')")
	}
	loc, err := time.LoadLocation(timezone)
	if err != nil {
		return nil, fmt.Errorf("could not load timezone '%s': %v", timezone, err)
	}
	return loc, nil
}

// HandleGetTimestamp handles the get_timestamp tool call.
func (h *Handlers) HandleGetTimestamp(ctx context.Context, request mcp.CallToolRequest, args GetTimestampArgs) (*mcp.CallToolResult, error) {
	if args.NaturalLanguageDate == "" {
		return reportMCPError("Missing or invalid required argument: natural_language_date")
	}
	loc, err := LoadLocation(h.config.Timezone)
	if err != nil {
		return reportMCPError(err.Error())
	}
	parsedTime, err := anytime.Parse(args.NaturalLanguageDate, time.Now().In(loc))
	if err != nil {
		return reportMCPError(fmt.Sprintf("Could not parse natural language date: %v", err))
	}
	return &mcp.CallToolResult{
		Content: []mcp.Content{
			mcp.TextContent{
				Type: "text",
				Text: parsedTime.Format(time.RFC3339),
			},
		},
	}, nil
}

// HandleListAreasAndGoals handles the list_areas_and_goals tool call.
func (h *Handlers) HandleListAreasAndGoals(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
	var b strings.Builder
	for _, area := range h.config.Areas {
		fmt.Fprintf(&b, "- %s: %s\n", area.GetName(), area.GetID())
		for _, goal := range area.GetGoals() {
			fmt.Fprintf(&b, "  - %s: %s\n", goal.GetName(), goal.GetID())
		}
	}
	return &mcp.CallToolResult{
		Content: []mcp.Content{
			mcp.TextContent{
				Type: "text",
				Text: b.String(),
			},
		},
	}, nil
}
