1package cmd
2
3import (
4 "encoding/json"
5 "fmt"
6 "os"
7
8 tea "github.com/charmbracelet/bubbletea"
9 "github.com/spf13/cobra"
10
11 "github.com/bnema/dumber/internal/cli/model"
12)
13
14var (
15 historyJSON bool
16 historyMax int
17)
18
19const defaultHistoryMax = 50
20
21var historyCmd = &cobra.Command{
22 Use: "history",
23 Short: "Browse and manage history",
24 Long: `Interactive history browser with timeline tabs, fuzzy search, and cleanup.`,
25 RunE: runHistory,
26}
27
28func init() {
29 rootCmd.AddCommand(historyCmd)
30
31 historyCmd.Flags().BoolVar(&historyJSON, "json", false, "output as JSON")
32 historyCmd.Flags().IntVar(&historyMax, "max", defaultHistoryMax, "maximum entries to show (for --json)")
33}
34
35func runHistory(_ *cobra.Command, _ []string) error {
36 app := GetApp()
37 if app == nil {
38 return fmt.Errorf("app not initialized")
39 }
40
41 // JSON output mode (non-interactive)
42 if historyJSON {
43 return runHistoryJSON()
44 }
45
46 // Interactive TUI mode
47 return runHistoryTUI()
48}
49
50// runHistoryTUI runs the interactive history browser.
51func runHistoryTUI() error {
52 app := GetApp()
53
54 m := model.NewHistoryModel(app.Ctx(), app.Theme, app.SearchHistoryUC)
55
56 p := tea.NewProgram(m, tea.WithAltScreen())
57 _, err := p.Run()
58 return err
59}
60
61// runHistoryJSON outputs history as JSON.
62func runHistoryJSON() error {
63 app := GetApp()
64
65 m := model.NewHistoryListModel(app.Ctx(), app.SearchHistoryUC, historyMax)
66
67 // Run briefly to load data
68 p := tea.NewProgram(m)
69 finalModel, err := p.Run()
70 if err != nil {
71 return fmt.Errorf("run model: %w", err)
72 }
73
74 // Extract results
75 listModel, ok := finalModel.(model.HistoryListModel)
76 if !ok {
77 return fmt.Errorf("unexpected model type")
78 }
79
80 if listModel.Error() != nil {
81 return listModel.Error()
82 }
83
84 // Output as JSON
85 entries := listModel.Entries()
86 enc := json.NewEncoder(os.Stdout)
87 enc.SetIndent("", " ")
88 return enc.Encode(entries)
89}
90
91// statsCmd shows history statistics.
92var statsCmd = &cobra.Command{
93 Use: "stats",
94 Short: "Show history statistics",
95 Long: `Display analytics about your browsing history.`,
96 RunE: runStats,
97}
98
99func init() {
100 historyCmd.AddCommand(statsCmd)
101}
102
103func runStats(_ *cobra.Command, _ []string) error {
104 app := GetApp()
105 if app == nil {
106 return fmt.Errorf("app not initialized")
107 }
108
109 // Run stats model
110 m := model.NewStatsModel(app.Theme, app.SearchHistoryUC)
111
112 p := tea.NewProgram(m)
113 _, err := p.Run()
114 return err
115}
116
117// clearCmd clears history.
118var clearCmd = &cobra.Command{
119 Use: "clear",
120 Short: "Clear history",
121 Long: `Interactively select time range to clear history.`,
122 RunE: runClear,
123}
124
125func init() {
126 historyCmd.AddCommand(clearCmd)
127}
128
129func runClear(_ *cobra.Command, _ []string) error {
130 app := GetApp()
131 if app == nil {
132 return fmt.Errorf("app not initialized")
133 }
134
135 // Run cleanup modal directly
136 m := model.NewCleanupModel(app.Theme, app.SearchHistoryUC)
137
138 p := tea.NewProgram(m)
139 _, err := p.Run()
140 return err
141}