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

package task

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 task by ID. Exported for potential use by shortcuts.
var ShowCmd = &cobra.Command{
	Use:   "show ID",
	Short: "Show task details",
	Long: `Show detailed information for a task.

Accepts a UUID or lunatask:// deep link.

Note: Due to end-to-end encryption, task name and notes
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
	}

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

	if mustGetBoolFlag(cmd, "json") {
		return outputTaskJSON(cmd, task)
	}

	return printTaskDetails(cmd, task)
}

func outputTaskJSON(cmd *cobra.Command, task *lunatask.Task) error {
	enc := json.NewEncoder(cmd.OutOrStdout())
	enc.SetIndent("", "  ")

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

	return nil
}

func printTaskDetails(cmd *cobra.Command, task *lunatask.Task) error {
	link, _ := lunatask.BuildDeepLink(lunatask.ResourceTask, task.ID)

	status := "unknown"
	if task.Status != nil {
		status = string(*task.Status)
	}

	fmt.Fprintf(cmd.OutOrStdout(), "%s\n", ui.H1.Render("Task: "+status))
	fmt.Fprintf(cmd.OutOrStdout(), "  ID:   %s\n", task.ID)
	fmt.Fprintf(cmd.OutOrStdout(), "  Link: %s\n", link)

	printAreaGoal(cmd, task)

	if task.ScheduledOn != nil {
		fmt.Fprintf(cmd.OutOrStdout(), "  Scheduled: %s\n", ui.FormatDate(task.ScheduledOn.Time))
	}

	if task.CompletedAt != nil {
		fmt.Fprintf(cmd.OutOrStdout(), "  Completed: %s\n", ui.FormatDate(*task.CompletedAt))
	}

	printTaskAttributes(cmd, task)

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

	return nil
}

func printAreaGoal(cmd *cobra.Command, task *lunatask.Task) {
	cfg, _ := config.Load()

	if task.AreaID != nil {
		areaDisplay := *task.AreaID
		if cfg != nil {
			if area := cfg.AreaByID(*task.AreaID); area != nil {
				areaDisplay = fmt.Sprintf("%s (%s)", area.Name, area.Key)
			}
		}

		fmt.Fprintf(cmd.OutOrStdout(), "  Area: %s\n", areaDisplay)
	}

	if task.GoalID != nil {
		goalDisplay := *task.GoalID
		if cfg != nil {
			if match := cfg.GoalByID(*task.GoalID); match != nil {
				goalDisplay = fmt.Sprintf("%s (%s)", match.Goal.Name, match.Goal.Key)
			}
		}

		fmt.Fprintf(cmd.OutOrStdout(), "  Goal: %s\n", goalDisplay)
	}
}

func printTaskAttributes(cmd *cobra.Command, task *lunatask.Task) {
	if task.Estimate != nil {
		fmt.Fprintf(cmd.OutOrStdout(), "  Estimate: %d min\n", *task.Estimate)
	}

	if task.Priority != nil && *task.Priority != lunatask.PriorityNormal {
		fmt.Fprintf(cmd.OutOrStdout(), "  Priority: %s\n", task.Priority)
	}

	if task.Progress != nil {
		fmt.Fprintf(cmd.OutOrStdout(), "  Progress: %d%%\n", *task.Progress)
	}

	if task.Motivation != nil && *task.Motivation != lunatask.MotivationUnknown {
		fmt.Fprintf(cmd.OutOrStdout(), "  Motivation: %s\n", *task.Motivation)
	}

	if task.Eisenhower != nil && *task.Eisenhower != lunatask.EisenhowerUncategorized {
		fmt.Fprintf(cmd.OutOrStdout(), "  Eisenhower: %s\n", formatEisenhower(*task.Eisenhower))
	}
}

func formatEisenhower(e lunatask.Eisenhower) string {
	switch e {
	case lunatask.EisenhowerUncategorized:
		return "uncategorized"
	case lunatask.EisenhowerDoNow:
		return "do now (important + urgent)"
	case lunatask.EisenhowerDoLater:
		return "do later (important)"
	case lunatask.EisenhowerDelegate:
		return "delegate (urgent)"
	case lunatask.EisenhowerEliminate:
		return "eliminate"
	default:
		return "unknown"
	}
}
