1package usecase
2
3import (
4 "context"
5
6 "github.com/bnema/dumber/internal/application/port"
7 "github.com/bnema/dumber/internal/logging"
8)
9
10// CheckConfigMigrationInput holds the input for checking config migration.
11type CheckConfigMigrationInput struct{}
12
13// CheckConfigMigrationOutput holds the result of the migration check.
14type CheckConfigMigrationOutput struct {
15 // NeedsMigration is true if there are missing keys.
16 NeedsMigration bool
17 // MissingKeys contains info about each missing key.
18 MissingKeys []port.KeyInfo
19 // ConfigFile is the path to the config file.
20 ConfigFile string
21}
22
23// DetectChangesInput holds the input for detecting config changes.
24type DetectChangesInput struct{}
25
26// DetectChangesOutput holds the result of change detection.
27type DetectChangesOutput struct {
28 // HasChanges is true if any changes were detected.
29 HasChanges bool
30 // Changes contains all detected changes.
31 Changes []port.KeyChange
32 // DiffText is a formatted diff-like string representation.
33 DiffText string
34}
35
36// MigrateConfigInput holds the input for migrating config.
37type MigrateConfigInput struct{}
38
39// MigrateConfigOutput holds the result of the migration.
40type MigrateConfigOutput struct {
41 // AddedKeys contains the keys that were added.
42 AddedKeys []string
43 // ConfigFile is the path to the config file.
44 ConfigFile string
45}
46
47// MigrateConfigUseCase handles config migration operations.
48type MigrateConfigUseCase struct {
49 migrator port.ConfigMigrator
50 diffFormatter port.DiffFormatter
51}
52
53// NewMigrateConfigUseCase creates a new migrate config use case.
54func NewMigrateConfigUseCase(migrator port.ConfigMigrator, diffFormatter port.DiffFormatter) *MigrateConfigUseCase {
55 return &MigrateConfigUseCase{
56 migrator: migrator,
57 diffFormatter: diffFormatter,
58 }
59}
60
61// Check checks if the user config is missing any default keys.
62func (uc *MigrateConfigUseCase) Check(ctx context.Context, _ CheckConfigMigrationInput) (*CheckConfigMigrationOutput, error) {
63 log := logging.FromContext(ctx)
64
65 result, err := uc.migrator.CheckMigration()
66 if err != nil {
67 log.Warn().Err(err).Msg("config migration check failed")
68 return nil, err
69 }
70
71 // No migration needed
72 if result == nil || len(result.MissingKeys) == 0 {
73 log.Debug().Msg("config is up to date, no migration needed")
74 return &CheckConfigMigrationOutput{
75 NeedsMigration: false,
76 MissingKeys: nil,
77 ConfigFile: "",
78 }, nil
79 }
80
81 // Build key info for each missing key
82 keyInfos := make([]port.KeyInfo, 0, len(result.MissingKeys))
83 for _, key := range result.MissingKeys {
84 keyInfos = append(keyInfos, uc.migrator.GetKeyInfo(key))
85 }
86
87 log.Debug().
88 Int("missing_keys", len(result.MissingKeys)).
89 Str("config_file", result.ConfigFile).
90 Msg("config migration check completed")
91
92 return &CheckConfigMigrationOutput{
93 NeedsMigration: true,
94 MissingKeys: keyInfos,
95 ConfigFile: result.ConfigFile,
96 }, nil
97}
98
99// DetectChanges detects all config changes and returns a diff-like output.
100func (uc *MigrateConfigUseCase) DetectChanges(ctx context.Context, _ DetectChangesInput) (*DetectChangesOutput, error) {
101 log := logging.FromContext(ctx)
102
103 changes, err := uc.migrator.DetectChanges()
104 if err != nil {
105 log.Warn().Err(err).Msg("config change detection failed")
106 return nil, err
107 }
108
109 if len(changes) == 0 {
110 log.Debug().Msg("no config changes detected")
111 return &DetectChangesOutput{
112 HasChanges: false,
113 Changes: nil,
114 DiffText: "No changes detected.",
115 }, nil
116 }
117
118 log.Debug().
119 Int("changes", len(changes)).
120 Msg("config changes detected")
121
122 return &DetectChangesOutput{
123 HasChanges: true,
124 Changes: changes,
125 DiffText: uc.diffFormatter.FormatChangesAsDiff(changes),
126 }, nil
127}
128
129// Execute adds missing default keys and removes deprecated keys from the user's config file.
130func (uc *MigrateConfigUseCase) Execute(ctx context.Context, _ MigrateConfigInput) (*MigrateConfigOutput, error) {
131 log := logging.FromContext(ctx)
132
133 // Check for any changes (added, removed, or renamed keys)
134 changes, err := uc.migrator.DetectChanges()
135 if err != nil {
136 return nil, err
137 }
138
139 if len(changes) == 0 {
140 log.Debug().Msg("no migration needed")
141 return &MigrateConfigOutput{
142 AddedKeys: nil,
143 ConfigFile: "",
144 }, nil
145 }
146
147 // Get config file path for output
148 configFile, _ := uc.migrator.GetConfigFile()
149
150 // Perform migration
151 appliedKeys, err := uc.migrator.Migrate()
152 if err != nil {
153 log.Error().Err(err).Msg("config migration failed")
154 return nil, err
155 }
156
157 log.Info().
158 Int("applied_keys", len(appliedKeys)).
159 Str("config_file", configFile).
160 Msg("config migration completed")
161
162 return &MigrateConfigOutput{
163 AddedKeys: appliedKeys,
164 ConfigFile: configFile,
165 }, nil
166}