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

package note

import (
	"encoding/json"
	"fmt"

	"git.secluded.site/go-lunatask"
	"git.secluded.site/lune/internal/client"
	"git.secluded.site/lune/internal/config"
	"git.secluded.site/lune/internal/ui"
	"git.secluded.site/lune/internal/validate"
	"github.com/spf13/cobra"
)

// ShowCmd displays a note by ID. Exported for potential use by shortcuts.
var ShowCmd = &cobra.Command{
	Use:   "show ID",
	Short: "Show note details",
	Long: `Show detailed information for a note.

Accepts a UUID or lunatask:// deep link.

Note: Due to end-to-end encryption, note name and content
are not available through the API. Only metadata is shown.`,
	Args: cobra.ExactArgs(1),
	RunE: runShow,
}

func init() {
	ShowCmd.Flags().Bool("json", false, "Output as JSON")
}

func runShow(cmd *cobra.Command, args []string) error {
	id, err := validate.Reference(args[0])
	if err != nil {
		return err
	}

	apiClient, err := client.New()
	if err != nil {
		return err
	}

	note, err := ui.Spin("Fetching note…", func() (*lunatask.Note, error) {
		return apiClient.GetNote(cmd.Context(), id)
	})
	if err != nil {
		return err
	}

	if mustGetBoolFlag(cmd, "json") {
		return outputNoteJSON(cmd, note)
	}

	return printNoteDetails(cmd, note)
}

func outputNoteJSON(cmd *cobra.Command, note *lunatask.Note) error {
	enc := json.NewEncoder(cmd.OutOrStdout())
	enc.SetIndent("", "  ")

	if err := enc.Encode(note); err != nil {
		return fmt.Errorf("encoding JSON: %w", err)
	}

	return nil
}

func printNoteDetails(cmd *cobra.Command, note *lunatask.Note) error {
	link, _ := lunatask.BuildDeepLink(lunatask.ResourceNote, note.ID)

	fmt.Fprintf(cmd.OutOrStdout(), "%s\n", ui.H1.Render("Note"))
	fmt.Fprintf(cmd.OutOrStdout(), "  ID:   %s\n", note.ID)
	fmt.Fprintf(cmd.OutOrStdout(), "  Link: %s\n", link)

	printNotebook(cmd, note)

	if note.DateOn != nil {
		fmt.Fprintf(cmd.OutOrStdout(), "  Date: %s\n", ui.FormatDate(note.DateOn.Time))
	}

	if note.Pinned {
		fmt.Fprintf(cmd.OutOrStdout(), "  Pinned: yes\n")
	}

	if len(note.Sources) > 0 {
		fmt.Fprintf(cmd.OutOrStdout(), "  Sources:\n")

		for _, src := range note.Sources {
			fmt.Fprintf(cmd.OutOrStdout(), "    - %s: %s\n", src.Source, src.SourceID)
		}
	}

	fmt.Fprintf(cmd.OutOrStdout(), "  Created: %s\n", ui.FormatDate(note.CreatedAt))
	fmt.Fprintf(cmd.OutOrStdout(), "  Updated: %s\n", ui.FormatDate(note.UpdatedAt))

	return nil
}

func printNotebook(cmd *cobra.Command, note *lunatask.Note) {
	if note.NotebookID == nil {
		return
	}

	notebookDisplay := *note.NotebookID
	cfg, _ := config.Load()

	if cfg != nil {
		if notebook := cfg.NotebookByID(*note.NotebookID); notebook != nil {
			notebookDisplay = fmt.Sprintf("%s (%s)", notebook.Name, notebook.Key)
		}
	}

	fmt.Fprintf(cmd.OutOrStdout(), "  Notebook: %s\n", notebookDisplay)
}
