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

// Package note provides the MCP resource handler for individual Lunatask notes.
package note

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

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

// ResourceTemplate is the URI template for note resources.
const ResourceTemplate = "lunatask://note/{id}"

// ResourceDescription describes the note resource for LLMs.
const ResourceDescription = `Reads metadata for a specific Lunatask note by ID or deep link.

Due to end-to-end encryption, note title and content are not available.
Returns metadata including notebook, date, pinned status, and sources.`

// sourceInfo represents a source reference in the response.
type sourceInfo struct {
	Source   string `json:"source"`
	SourceID string `json:"source_id"`
}

// noteInfo represents note metadata in the resource response.
type noteInfo struct {
	DeepLink   string       `json:"deep_link"`
	NotebookID *string      `json:"notebook_id,omitempty"`
	DateOn     *string      `json:"date_on,omitempty"`
	Pinned     bool         `json:"pinned"`
	Sources    []sourceInfo `json:"sources,omitempty"`
	CreatedAt  string       `json:"created_at"`
	UpdatedAt  string       `json:"updated_at"`
}

// Handler handles note resource requests.
type Handler struct {
	client *lunatask.Client
}

// NewHandler creates a new note resource handler.
func NewHandler(accessToken string) *Handler {
	return &Handler{
		client: lunatask.NewClient(accessToken, lunatask.UserAgent("lune-mcp/1.0")),
	}
}

// HandleRead returns metadata for a specific note.
func (h *Handler) HandleRead(
	ctx context.Context,
	req *mcp.ReadResourceRequest,
) (*mcp.ReadResourceResult, error) {
	_, id, err := lunatask.ParseReference(req.Params.URI)
	if err != nil {
		return nil, fmt.Errorf("invalid URI %q: %w", req.Params.URI, mcp.ResourceNotFoundError(req.Params.URI))
	}

	note, err := h.client.GetNote(ctx, id)
	if err != nil {
		return nil, fmt.Errorf("fetching note: %w", err)
	}

	info := buildNoteInfo(note)

	data, err := json.MarshalIndent(info, "", "  ")
	if err != nil {
		return nil, fmt.Errorf("marshaling note: %w", err)
	}

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

func buildNoteInfo(note *lunatask.Note) noteInfo {
	info := noteInfo{
		NotebookID: note.NotebookID,
		Pinned:     note.Pinned,
		CreatedAt:  note.CreatedAt.Format(time.RFC3339),
		UpdatedAt:  note.UpdatedAt.Format(time.RFC3339),
	}

	info.DeepLink, _ = lunatask.BuildDeepLink(lunatask.ResourceNote, note.ID)

	if note.DateOn != nil {
		s := note.DateOn.Format("2006-01-02")
		info.DateOn = &s
	}

	if len(note.Sources) > 0 {
		info.Sources = make([]sourceInfo, 0, len(note.Sources))
		for _, src := range note.Sources {
			info.Sources = append(info.Sources, sourceInfo{
				Source:   src.Source,
				SourceID: src.SourceID,
			})
		}
	}

	return info
}
