kasl-cli 1.0.1

kasl is a comprehensive command-line utility 🛠️ designed to streamline the tracking of work activities 📊, including start times ⏰, pauses ⏸, and task completion
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
//! Display implementation for kasl application messages.
//!
//! Provides the core `Display` trait implementation for the `Message` enum, enabling automatic conversion of structured message data into human-readable text.
//!
//! ## Features
//!
//! - **Single Source of Truth**: All message text is defined in one location
//! - **Type Safety**: Compile-time verification of message parameter usage
//! - **Internationalization Ready**: Structured for future localization support
//! - **Consistent Formatting**: Uniform message presentation across the application
//! - **Parameter Interpolation**: Safe string formatting with typed parameters
//!
//! ## Usage
//!
//! ```rust
//! use kasl::libs::messages::types::Message;
//!
//! let message = Message::TaskCreated;
//! println!("{}", message);
//!
//! let parameterized = Message::MonitorStarted {
//!     pause_threshold: 60,
//!     poll_interval: 500,
//!     activity_threshold: 30,
//! };
//! println!("{}", parameterized);
//! ```

use super::types::Message;
use std::fmt::{Display, Formatter, Result};

impl Display for Message {
    /// Converts a `Message` enum variant into human-readable text.
    ///
    /// This method implements the core message-to-text conversion logic for
    /// the entire kasl application. It provides consistent, professional
    /// text formatting for all user-facing messages while maintaining
    /// type safety and parameter interpolation.
    ///
    /// ## Implementation Strategy
    ///
    /// The method uses a comprehensive match statement to handle each message
    /// variant individually, ensuring that:
    /// - All message types are explicitly handled
    /// - Parameter interpolation is type-safe
    /// - Text formatting is consistent across message categories
    /// - New message types require explicit formatting decisions
    ///
    /// ## Text Quality Standards
    ///
    /// All generated text adheres to these quality standards:
    /// - **Clarity**: Messages are easily understood by users
    /// - **Specificity**: Include relevant details and context
    /// - **Actionability**: Provide guidance for next steps when appropriate
    /// - **Professionalism**: Suitable for business and personal environments
    /// - **Consistency**: Uniform tone and style across all messages
    ///
    /// ## Parameter Handling
    ///
    /// Messages with parameters use safe string interpolation:
    /// - String parameters are inserted directly
    /// - Numeric parameters are formatted appropriately
    /// - Collections are joined with appropriate separators
    /// - Optional values are handled with meaningful defaults
    ///
    /// ## Error Message Philosophy
    ///
    /// Error messages are designed to be helpful rather than technical:
    /// - Focus on user-understandable problems
    /// - Suggest concrete resolution steps
    /// - Avoid intimidating technical jargon
    /// - Provide sufficient context for troubleshooting
    ///
    /// # Arguments
    ///
    /// * `f` - The formatter for writing the text output
    ///
    /// # Returns
    ///
    /// Returns `Ok(())` if the message was successfully formatted,
    /// or an error if the formatting operation fails.
    ///
    /// # Error Scenarios
    ///
    /// - **Formatter Errors**: Underlying write operations fail
    /// - **Memory Allocation**: Insufficient memory for string operations
    /// - **Parameter Formatting**: Invalid parameter values (rare)
    ///
    /// # Examples
    ///
    /// ```rust
    /// use kasl::libs::messages::Message;
    ///
    /// // Automatic formatting through Display trait
    /// let message = Message::TaskCreated;
    /// println!("{}", message); // "Task created successfully"
    ///
    /// // With parameters
    /// let date_message = Message::WorkdayStarting("2025-01-15".to_string());
    /// println!("{}", date_message); // "Starting workday for 2025-01-15"
    /// ```
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let text = match self {
            // === AUTOSTART MESSAGES ===
            Message::AutostartEnabled => "Autostart has been enabled. Kasl will start automatically on system boot.".to_string(),
            Message::AutostartEnabledUser => "Autostart has been enabled for current user. Kasl will start when you log in.".to_string(),
            Message::AutostartDisabled => "Autostart has been disabled.".to_string(),
            Message::AutostartAlreadyDisabled => "Autostart was already disabled.".to_string(),
            Message::AutostartEnableFailed(error) => format!("Failed to enable autostart: {}", error),
            Message::AutostartDisableFailed(error) => format!("Failed to disable autostart: {}", error),
            Message::AutostartStatus(status) => format!("Autostart is currently: {}", status),
            Message::AutostartNotImplemented => "Autostart is not yet implemented for this operating system.".to_string(),
            Message::AutostartRequiresAdmin => "Administrator privileges required for system-level autostart. Trying user-level alternative...".to_string(),
            Message::AutostartCheckingAlternative => "Checking alternative autostart method...".to_string(),

            // === TASK MESSAGES ===
            Message::TaskCreated => "Task created successfully".to_string(),
            Message::TaskUpdated => "Task updated successfully".to_string(),
            Message::TaskDeleted => "Task deleted successfully".to_string(),
            Message::TaskNotFound => "Task not found".to_string(),
            Message::TaskCreateFailed => "Failed to create task".to_string(),
            Message::TaskUpdateFailed => "Failed to update task".to_string(),
            Message::TaskDeleteFailed => "Failed to delete task".to_string(),
            Message::TasksDeletedCount(count) => format!("Deleted {} task(s) successfully.", count),
            Message::TasksNotFoundForDate(date) => format!("Tasks not found for {}, report not sent.", date),
            Message::TasksNotFoundSad => "No tasks found.".to_string(),
            Message::TasksHeader => "Tasks:".to_string(),
            Message::TasksIncompleteHeader => "Incomplete tasks".to_string(),
            Message::TasksGitlabHeader => "Gitlab commits".to_string(),
            Message::TasksJiraHeader => "Jira issues".to_string(),
            Message::TasksDiscoverySummary { incomplete, jira, gitlab } => {
                let mut parts = Vec::new();
                if *incomplete > 0 {
                    parts.push(format!("{} incomplete", incomplete));
                }
                if *jira > 0 {
                    parts.push(format!("{} jira", jira));
                }
                if *gitlab > 0 {
                    parts.push(format!("{} gitlab", gitlab));
                }
                format!("Found: {}", parts.join(", "))
            }
            Message::TasksDiscoverySeparator => "──────── other ────────".to_string(),
            Message::TasksDiscoverySearchingIncomplete => "Looking for incomplete tasks...".to_string(),
            Message::TasksDiscoveryFetchingExternal => "Fetching GitLab commits and Jira issues...".to_string(),
            Message::NoTaskIdsProvided => "No task IDs provided for deletion.".to_string(),
            Message::TasksNotFoundForIds(ids) => format!("No tasks found with IDs: {:?}", ids),
            Message::TasksToBeDeleted => "The following tasks will be deleted:".to_string(),
            Message::ConfirmDeleteTask => "Are you sure you want to delete this task?".to_string(),
            Message::ConfirmDeleteTasks(count) => format!("Are you sure you want to delete {} tasks?", count),
            Message::ConfirmDeleteAllTodayTasks(count) => format!("Are you sure you want to delete ALL {} tasks for today?", count),
            Message::ConfirmDeleteAllTodayTasksFinal => "This action cannot be undone. Are you REALLY sure?".to_string(),
            Message::NoTasksForToday => "No tasks found for today.".to_string(),
            Message::TaskNotFoundWithId(id) => format!("Task with ID {} not found.", id),
            Message::CurrentTaskState => "Current task:".to_string(),
            Message::TaskEditPreview => "Task after changes:".to_string(),
            Message::ConfirmTaskUpdate => "Save changes?".to_string(),
            Message::NoChangesDetected => "No changes detected.".to_string(),
            Message::NoTasksSelected => "No tasks selected for editing.".to_string(),
            Message::SelectTasksToEdit => "Select tasks to edit (space to select, enter to confirm)".to_string(),
            Message::EditingTask(name) => format!("Editing task: {}", name),
            Message::TaskUpdatedWithName(name) => format!("Task '{}' updated successfully.", name),
            Message::TaskSkippedNoChanges(name) => format!("Task '{}' - no changes, skipped.", name),
            Message::TaskEditingCompleted => "Task editing completed.".to_string(),
            Message::PromptTaskNameEdit => "Task name".to_string(),
            Message::PromptTaskCommentEdit => "Comment (optional)".to_string(),
            Message::PromptTaskCompletenessEdit => "Completeness (0-100)".to_string(),
            Message::TaskCompletenessRange => "Completeness must be between 0 and 100".to_string(),

            // === WORKDAY MESSAGES ===
            Message::WorkdayEnded => "Workday ended for today.".to_string(),
            Message::WorkdayNotFound => "No workday record found".to_string(),
            Message::WorkdayNotFoundForDate(date) => format!("No workday record found for {}", date),
            Message::WorkdayCreateFailed => "Failed to create workday".to_string(),
            Message::WorkdayStarting(date) => format!("Starting workday for {}", date),
            Message::WorkdayCouldNotFindAfterFinalizing(date) => {
                format!("Could not find workday for {} after finalizing.", date)
            }

            // === CONFIGURATION MESSAGES ===
            Message::ConfigSaved => "Configuration saved successfully".to_string(),
            Message::ConfigDeleted => "Configuration deleted successfully".to_string(),
            Message::ConfigLoaded => "Configuration loaded successfully".to_string(),
            Message::ConfigFileNotFound => "Configuration file not found".to_string(),
            Message::ConfigParseError => "Failed to parse configuration".to_string(),
            Message::ConfigSaveError => "Failed to save configuration".to_string(),
            Message::ConfigModuleGitLab => "GitLab settings".to_string(),
            Message::ConfigModuleJira => "Jira settings".to_string(),
            Message::ConfigModuleSiServer => "SiServer settings".to_string(),
            Message::ConfigModuleMonitor => "Monitor settings".to_string(),
            Message::ConfigModuleServer => "Server settings".to_string(),
            Message::ConfigModuleProductivity => "Productivity settings".to_string(),
            Message::ConfigModuleTaskDiscovery => "Task discovery settings".to_string(),
            Message::ConfigModuleJiraInbox => "Jira inbox settings".to_string(),
            Message::TaskDiscoveryIgnoreListHeader => "Current ignore list:".to_string(),
            Message::TaskDiscoveryIgnoreListEmpty => "Ignore list is empty.".to_string(),
            Message::TaskDiscoveryIgnoreNameAdded(name) => format!("Added '{}' to ignore list.", name),
            Message::TaskDiscoveryIgnoreNameExists(name) => format!("'{}' is already in the ignore list.", name),
            Message::TaskDiscoveryIgnoreNamesAdded(count) => {
                format!("Added {} name(s) to the discovery ignore list.", count)
            }

            // === REPORT MESSAGES ===
            Message::DailyReportSent(date) => {
                format!(
                    "Your report dated {} has been successfully submitted\nWait for a message to your email address",
                    date
                )
            }
            Message::MonthlyReportSent(date) => {
                format!(
                    "Your monthly report dated {} has been successfully submitted\nWait for a message to your email address",
                    date
                )
            }
            Message::MonthlyReportTriggered => "It's the last working day of the month. Submitting the monthly report as well...".to_string(),
            Message::ReportSendFailed(status) => format!("Failed to send report. Status: {}", status),
            Message::MonthlyReportSendFailed(status) => format!("Failed to send monthly report. Status: {}", status),
            Message::ReportHeader(date) => format!("Report for {}", date),
            Message::WorkingHoursForMonth(month_year) => format!("Working hours for {}", month_year),

            // === EXPORT MESSAGES ===
            Message::ExportingData(data, format) => format!("Exporting {} in {} format...", data, format),
            Message::ExportCompleted(path) => format!("Export completed successfully: {}", path),
            Message::ExportingAllData => "Exporting all data...".to_string(),
            Message::ExportFailed(error) => format!("Export failed: {}", error),

            // === TEMPLATE MESSAGES ===
            Message::TemplateCreated(name) => format!("Template '{}' created successfully.", name),
            Message::TemplateUpdated(name) => format!("Template '{}' updated successfully.", name),
            Message::TemplateDeleted(name) => format!("Template '{}' deleted successfully.", name),
            Message::TemplateNotFound(name) => format!("Template '{}' not found.", name),
            Message::TemplateAlreadyExists(name) => format!("Template '{}' already exists.", name),
            Message::TemplateCreateFailed => "Failed to create template.".to_string(),
            Message::NoTemplatesFound => "No templates found.".to_string(),
            Message::TemplateListHeader => "Task Templates:".to_string(),
            Message::SelectTemplateToEdit => "Select template to edit".to_string(),
            Message::SelectTemplateToDelete => "Select template to delete".to_string(),
            Message::ConfirmDeleteTemplate(name) => format!("Delete template '{}'?", name),
            Message::EditingTemplate(name) => format!("Editing template: {}", name),
            Message::NoTemplatesMatchingQuery(query) => format!("No templates matching '{}'", query),
            Message::TemplateSearchResults(query) => format!("Templates matching '{}':", query),
            Message::SelectTemplateAction => "What would you like to do?".to_string(),
            Message::PromptTemplateName => "Template name (unique identifier)".to_string(),
            Message::PromptTemplateTaskName => "Task name".to_string(),
            Message::PromptTemplateComment => "Comment (optional)".to_string(),
            Message::PromptTemplateCompleteness => "Default completeness (0-100)".to_string(),
            Message::CreatingTaskFromTemplate(name) => format!("Creating task from template '{}'", name),
            Message::SelectTemplate => "Select a template".to_string(),
            Message::CreateTemplateFirst => "Create templates with 'kasl template add'".to_string(),

            // === TAG MESSAGES ===
            Message::TagCreated(name) => format!("Tag '{}' created successfully.", name),
            Message::TagUpdated(name) => format!("Tag '{}' updated successfully.", name),
            Message::TagDeleted(name) => format!("Tag '{}' deleted successfully.", name),
            Message::TagNotFound(name) => format!("Tag '{}' not found.", name),
            Message::TagAlreadyExists(name) => format!("Tag '{}' already exists.", name),
            Message::NoTagsFound => "No tags found.".to_string(),
            Message::TagListHeader => "Tags:".to_string(),
            Message::EditingTag(name) => format!("Editing tag: {}", name),
            Message::SelectTagAction => "What would you like to do?".to_string(),
            Message::SelectTagToEdit => "Select tag to edit".to_string(),
            Message::SelectTagToDelete => "Select tag to delete".to_string(),
            Message::ConfirmDeleteTag(name) => format!("Delete tag '{}'?", name),
            Message::ConfirmDeleteTagWithTasks(name, count) => format!("Tag '{}' is used by {} task(s). Delete anyway?", name, count),
            Message::PromptTagName => "Tag name".to_string(),
            Message::PromptTagColor => "Tag color (e.g., blue, green, red)".to_string(),
            Message::NoTasksWithTag(tag) => format!("No tasks found with tag '{}'.", tag),
            Message::TasksWithTag(tag) => format!("Tasks with tag '{}':", tag),
            Message::TagsAddedToTask(tags) => format!("Tags added: {}", tags),

            // === SHORT INTERVALS MESSAGES ===
            Message::ShortIntervalsDetected(count, duration) => format!("Found {} short work intervals (total: {})", count, duration),
            Message::NoShortIntervalsFound(min) => format!("No work intervals shorter than {} minutes found.", min),
            Message::ShortIntervalsToRemove(count) => format!("Found {} short intervals to remove:", count),
            Message::RemovingPauses(count) => format!("Removing {} pauses to merge intervals...", count),
            Message::ShortIntervalsCleared(count) => format!("Successfully removed {} pauses and merged intervals.", count),
            Message::NoRemovablePausesFound => "No pauses found that can be removed to clear short intervals.".to_string(),
            Message::UpdatedReport => "Updated report:".to_string(),
            Message::PromptMinWorkInterval => "Minimum work interval (minutes)".to_string(),

            // === TIME ADJUSTMENT MESSAGES ===
            Message::SelectAdjustmentMode => "Select adjustment mode".to_string(),
            Message::PromptAdjustmentMinutes => "How many minutes to adjust?".to_string(),
            Message::PromptPauseStartTime => "When should the pause start? (HH:MM)".to_string(),
            Message::ConfirmTimeAdjustment => "Apply this time adjustment?".to_string(),
            Message::TimeAdjustmentApplied => "Time adjustment applied successfully.".to_string(),
            Message::AdjustmentPreview => "Time adjustment preview:".to_string(),
            Message::InvalidAdjustmentTooMuchTime => "Cannot adjust that much time - would result in invalid workday.".to_string(),
            Message::InvalidPauseOutsideWorkday => "Pause must be within workday hours.".to_string(),
            Message::WorkdayUpdateFailed => "Failed to update workday.".to_string(),

            // === PAUSE MESSAGES ===
            Message::PausesTitle(date) => format!("Pauses for {}", date),

            // === MONITOR MESSAGES ===
            Message::MonitorStarted {
                pause_threshold,
                poll_interval,
                activity_threshold,
            } => {
                format!(
                    "Monitor is running with pause threshold {}s, poll interval {}ms, activity threshold {}s",
                    pause_threshold, poll_interval, activity_threshold
                )
            }
            Message::MonitorStopped => "Monitor stopped".to_string(),
            Message::MonitorStartFailed => "Failed to start monitor".to_string(),
            Message::MonitorStopFailed => "Failed to stop monitor".to_string(),
            Message::MonitorExitedNormally => "Monitor exited normally".to_string(),
            Message::MonitorShuttingDown => "Shutting down monitor...".to_string(),
            Message::MonitorError(error) => format!("Monitor error: {}", error),
            Message::MonitorTaskPanicked(error) => format!("Monitor task panicked: {}", error),
            Message::PauseStarted => "Pause Start".to_string(),
            Message::PauseEnded => "Pause End".to_string(),

            // === WATCHER/DAEMON MESSAGES ===
            Message::WatcherStarted(pid) => format!("Watcher started in the background (PID: {}).", pid),
            Message::WatcherStopped(pid) => format!("Watcher process (PID: {}) stopped successfully.", pid),
            Message::WatcherStoppedSuccessfully => "Watcher stopped successfully".to_string(),
            Message::WatcherNotRunning => "Watcher is not running.".to_string(),
            Message::WatcherNotRunningPidNotFound => "Watcher does not appear to be running (PID file not found).".to_string(),
            Message::WatcherStartingForeground => "Starting watcher in foreground... Press Ctrl+C to exit.".to_string(),
            Message::WatcherStoppingExisting(pid) => format!("Stopping existing watcher (PID: {})...", pid),
            Message::WatcherFailedToStopExisting(error) => format!("Warning: Failed to stop existing daemon: {}", error),
            Message::WatcherFailedToStop(pid) => format!("Failed to stop watcher process (PID: {})", pid),
            Message::WatcherReceivedSigterm => "Received SIGTERM, shutting down gracefully...".to_string(),
            Message::WatcherReceivedSigint => "Received SIGINT, shutting down gracefully...".to_string(),
            Message::WatcherReceivedCtrlC => "Received Ctrl+C, shutting down gracefully...".to_string(),
            Message::WatcherCtrlCListenFailed(error) => format!("Failed to listen for Ctrl+C: {}", error),
            Message::WatcherSignalHandlingNotSupported => "Warning: Signal handling not supported on this platform".to_string(),
            Message::DaemonModeNotSupported => "Daemon mode is not supported on this platform.".to_string(),
            Message::FailedToGetCurrentExecutable => "Failed to get the path of the current executable".to_string(),
            Message::FailedToCreateSigtermHandler => "Failed to create SIGTERM handler".to_string(),
            Message::FailedToCreateSigintHandler => "Failed to create SIGINT handler".to_string(),

            // === UPDATE MESSAGES ===
            Message::UpdateAvailable { app_name, latest } => {
                format!(
                    "A new version of {} is available: v{}\nUpgrade now by running: {} update",
                    app_name, latest, app_name
                )
            }
            Message::UpdateCompleted { app_name, version } => {
                format!("The {} application has been successfully updated to version {}!", app_name, version)
            }
            Message::NoUpdateRequired => "No update required. You are using the latest version!".to_string(),
            Message::UpdateDownloadUrlNotSet => "Download URL not set".to_string(),
            Message::WatcherStoppingForUpdate => "Stopping watcher for update...".to_string(),
            Message::WatcherRestartingAfterUpdate => "Restarting watcher after update...".to_string(),
            Message::WatcherStoppingForConfig => "Stopping watcher to apply new configuration...".to_string(),
            Message::WatcherRestartingAfterConfig => "Restarting watcher with updated configuration...".to_string(),
            Message::WatcherRestarted => "Watcher successfully restarted with new configuration".to_string(),
            Message::WatcherRestartFailed { error } => format!("Warning: Failed to restart watcher: {}", error),
            Message::UpdateBinaryNotFoundInArchive => "Binary not found in the release archive.".to_string(),

            // === AUTHENTICATION MESSAGES ===
            Message::WrongPassword(count) => format!("You entered the wrong password {} times!", count),
            Message::InvalidCredentials => "Invalid credentials".to_string(),
            Message::SessionExpired => "Session expired".to_string(),
            Message::AuthenticationFailed(service) => format!("Authentication failed: {}", service),
            Message::JiraAuthenticateFailed => "Jira authenticate failed".to_string(),
            Message::LoginFailed => "Login failed".to_string(),
            Message::CredentialsNotSet => "Credentials not set!".to_string(),

            // === API MESSAGES ===
            Message::ApiConnectionFailed => "Failed to connect to API".to_string(),
            Message::ApiAuthFailed => "API authentication failed".to_string(),
            Message::ApiRequestFailed => "API request failed".to_string(),
            Message::GitlabFetchFailed(error) => format!("[kasl] Failed to get GitLab events: {}", error),
            Message::GitlabUserIdFailed(error) => format!("[kasl] Failed to get GitLab user ID: {}", error),
            Message::JiraFetchFailed(error) => format!("[kasl] Failed to get Jira issues: {}", error),
            Message::SiServerConfigNotFound => "SiServer configuration not found in config file.".to_string(),
            Message::SiServerSessionFailed(error) => format!("[kasl] Failed to get SiServer session for rest dates: {}", error),
            Message::SiServerRestDatesFailed(error) => format!("[kasl] Failed to request rest dates: {}", error),
            Message::SiServerRestDatesParsingFailed(error) => format!("[kasl] Failed to parse rest dates response: {}", error),

            // === DATABASE MESSAGES ===
            Message::DbConnectionFailed => "Failed to connect to database".to_string(),
            Message::DbQueryFailed => "Database query failed".to_string(),
            Message::DbMigrationFailed => "Database migration failed".to_string(),
            Message::DatabaseOperationFailed { operation, error } => {
                format!("Database operation '{}' failed (continuing monitoring): {}", operation, error)
            }
            Message::NoIdSet => "No ID set".to_string(),

            // === FILE SYSTEM MESSAGES ===
            Message::FileNotFound => "File not found".to_string(),
            Message::FileReadError => "Failed to read file".to_string(),
            Message::FileWriteError => "Failed to write file".to_string(),
            Message::InvalidPidFileContent => "Invalid PID file content".to_string(),
            Message::DataStoragePathError => "DataStorage get_path error".to_string(),

            // === SYSTEM/PATH MESSAGES ===
            Message::PathConfigured => "PATH successfully configured for system-wide access".to_string(),
            Message::PathConfigWarning { error } => format!(
                "Warning: Could not configure PATH automatically. {}\nYou may need to run as administrator or manually add kasl to your PATH.",
                error
            ),
            Message::PathQueryFailed(status) => format!("Failed to query PATH from registry: {:?}", status),
            Message::PathSetFailed => "Failed to set PATH in registry".to_string(),
            Message::PathRegistryQueryError { status } => format!("Registry query failed (exit code: {})", status),
            Message::PathRegistryUpdateError { status, stderr } => {
                if stderr.trim().is_empty() {
                    format!("Registry update failed (exit code: {})", status)
                } else {
                    format!("Registry update failed (exit code: {}): {}", status, stderr.trim())
                }
            }
            Message::FailedToJoinPaths => "Failed to join paths".to_string(),
            Message::FailedToExecuteRegQuery => "Failed to execute reg query".to_string(),
            Message::FailedToParseRegOutput => "Failed to parse reg query output".to_string(),
            Message::FailedToGetPathFromReg => "Failed to get PATH value from reg query".to_string(),
            Message::FailedToExecuteRegSet => "Failed to execute reg set".to_string(),
            Message::FailedToOpenProcess(code) => format!("Failed to open process: error code {}", code),
            Message::FailedToTerminateProcess(code) => format!("Failed to terminate process: error code {}", code),
            Message::ProcessNotFound => "Process doesn't exist".to_string(),
            Message::ProcessTerminationNotSupported => "Process termination not supported on this platform".to_string(),

            // === PRODUCTIVITY MESSAGES ===
            Message::MonthlyProductivity(percentage) => format!("Monthly work productivity: {:.1}%", percentage),
            Message::LowProductivityWarning { current, threshold } => {
                format!(
                    "🔴 LOW PRODUCTIVITY: {:.1}% (minimum: {:.1}%)\n   If an absence is missing from the day, record it: kasl pauses add --start HH:MM --minutes N",
                    current, threshold
                )
            }
            Message::ProductivityTooLowToSend { current, threshold } => {
                format!(
                    "Cannot send report: productivity {:.1}% is below minimum {:.1}%\nIf an absence is missing from the day, record it: kasl pauses add --start HH:MM --minutes N",
                    current, threshold
                )
            }
            Message::ManualPauseCreated {
                start_time,
                end_time,
                duration_minutes,
            } => {
                format!("Pause recorded: {} - {} ({} minutes)", start_time, end_time, duration_minutes)
            }
            Message::ManualPauseOverlaps { start_time, end_time } => {
                format!("Overlaps an existing pause ({} - {})", start_time, end_time)
            }
            Message::ManualPauseRemoved(id) => format!("Pause {} removed", id),
            Message::ManualPauseNotFound(id) => format!("no pause with id '{}' - see `kasl pauses list`", id),
            Message::ProductivityRecalculated(percentage) => format!("Productivity recalculated: {:.1}%", percentage),

            // === ENCRYPTION/SECRET MESSAGES ===
            Message::EncryptionKeyMustBeSet => "ENCRYPTION_KEY must be set".to_string(),
            Message::EncryptionIvMustBeSet => "ENCRYPTION_IV must be set".to_string(),

            // === PROMPTS ===
            Message::PromptTaskName => "Enter task name (multi-line paste OK)".to_string(),
            Message::TaskNameMergedFromPaste => "Merged pasted lines into the task name.".to_string(),
            Message::PromptTaskComment => "Enter comment".to_string(),
            Message::PromptTaskCompleteness => "Enter completeness".to_string(),
            Message::PromptGitlabToken => "Enter your GitLab private token".to_string(),
            Message::PromptGitlabUrl => "Enter the GitLab API URL".to_string(),
            Message::PromptJiraLogin => "Enter your Jira login".to_string(),
            Message::PromptJiraUrl => "Enter the Jira API URL".to_string(),
            Message::PromptJiraPassword => "Enter your Jira password".to_string(),
            Message::PromptSiLogin => "Enter your SiServer login".to_string(),
            Message::PromptSiAuthUrl => "Enter your SiServer login URL".to_string(),
            Message::PromptSiApiUrl => "Enter the SiServer API URL".to_string(),
            Message::PromptSiPassword => "Enter your SiServer password".to_string(),
            Message::PromptMinPauseDuration => "Enter minimum pause duration (minutes)".to_string(),
            Message::PromptPauseThreshold => "Enter pause threshold (seconds)".to_string(),
            Message::PromptPollInterval => "Enter poll interval (milliseconds)".to_string(),
            Message::PromptActivityThreshold => "Enter activity threshold (seconds)".to_string(),
            Message::PromptMinProductivityThreshold => "Enter minimum productivity threshold (%)".to_string(),
            Message::PromptWorkdayHours => "Enter expected workday duration (hours)".to_string(),
            Message::PromptMinWorkdayFraction => "Enter minimum workday fraction before suggesting breaks (0.0-1.0)".to_string(),
            Message::PromptServerApiUrl => "Enter server API URL".to_string(),
            Message::PromptServerAuthToken => "Enter server auth token".to_string(),
            Message::PromptConfirmDelete => "Are you sure you want to delete this item?".to_string(),
            Message::PromptSelectOptions => "Select options".to_string(),
            Message::PromptSelectModules => "Select nodes to configure".to_string(),
            Message::PromptSelectTasks => "Select tasks".to_string(),
            Message::PromptSelectTasksToEdit => "Select tasks to edit".to_string(),
            Message::PromptSelectTasksToImport => "Select tasks to import".to_string(),
            Message::PromptSelectTasksToIgnore => "Select tasks to ignore (optional)".to_string(),
            Message::PromptSelectIgnoreNamesToRemove => "Select ignore names to remove (optional)".to_string(),
            Message::PromptAddIgnoreName => "Add ignore name (empty to finish)".to_string(),

            // === GENERAL MESSAGES ===
            Message::OperationCompleted => "Operation completed successfully".to_string(),
            Message::OperationCancelled => "Operation cancelled".to_string(),
            Message::DataExported => "Data exported successfully".to_string(),
            Message::BackupCreated => "Backup created successfully".to_string(),
            Message::InvalidInput => "Invalid input provided".to_string(),
            Message::PermissionDenied => "Permission denied".to_string(),

            // === ERROR LOGGING ===
            Message::ErrorSendingEvents(error) => format!("[kasl] Error sending events: {}", error),
            Message::ErrorSendingMonthlyReport(error) => format!("[kasl] Error sending monthly report: {}", error),
            Message::ErrorInRdevListener(error) => format!("Error in rdev listener: {:?}", error),
            Message::ErrorRequestingRestDates(error) => format!("Error requesting rest dates: {}", error),

            // === SPECIFIC UI MESSAGES ===
            Message::SelectingTask(name) => format!("Selected task: {}", name),
            Message::SelectedTaskFormat(name, completeness) => format!("{} - {}%", name, completeness),

            // === JIRA INBOX MESSAGES ===
            Message::JiraInboxRequiresJiraConfig => "Jira inbox requires Jira to be configured. Run `kasl init` and select Jira.".to_string(),
            Message::JiraInboxEmpty => "Jira inbox is empty.".to_string(),
            Message::JiraInboxListHeader => "Jira inbox:".to_string(),
            Message::JiraInboxSynced { fetched, new_count, updated } => {
                format!("Jira inbox synced: {} fetched, {} new, {} updated.", fetched, new_count, updated)
            }
            Message::JiraInboxNewIssues(count) => format!("Jira inbox: {} new issue(s).", count),
            Message::JiraInboxNotFound(key) => format!("Issue '{}' not found in inbox.", key),
            Message::JiraInboxPinned(key) => format!("Pinned {}.", key),
            Message::JiraInboxUnpinned(key) => format!("Unpinned {}.", key),
            Message::JiraInboxDismissed(key) => format!("Dismissed {}.", key),
            Message::JiraInboxOpened(key) => format!("Opened {} in browser.", key),
            Message::JiraInboxTaken(key) => format!("Imported {} into tasks.", key),
            Message::JiraInboxOpenFailed(err) => format!("Failed to open browser: {}", err),
            Message::PromptJiraInboxEnabled => "Enable Jira inbox polling?".to_string(),
            Message::PromptJiraInboxPollInterval => "Jira inbox poll interval (seconds)".to_string(),
            Message::PromptJiraInboxNotify => "Show toast notifications for new issues?".to_string(),
            Message::PromptJiraInboxSortFieldId => "Sort field id for ranking (e.g. customfield_12345 for Scoring; empty to skip)".to_string(),
            Message::PromptJiraInboxSortFieldLabel => "Label for sort field (default Scoring)".to_string(),
            Message::PromptJiraInboxExtraFieldId => "Additional custom field id to fetch (empty to finish)".to_string(),
            Message::PromptJiraInboxExtraFieldLabel => "Label for this custom field".to_string(),

            // === MIGRATION MESSAGES ===
            Message::MigrationsFound(count) => format!("Found {} pending database migrations", count),
            Message::RunningMigration(version, name) => format!("Running migration v{}: {}", version, name),
            Message::MigrationCompleted(version) => format!("✓ Migration v{} completed", version),
            Message::MigrationFailed(version, error) => format!("✗ Migration v{} failed: {}", version, error),
            Message::AllMigrationsCompleted => "All database migrations completed successfully".to_string(),
            Message::DatabaseVersion(version) => format!("Current database version: {}", version),
            Message::DatabaseUpToDate => "Database schema is up to date".to_string(),
            Message::DatabaseNeedsUpdate => "Database schema needs to be updated".to_string(),
            Message::MigrationHistory => "Migration history:".to_string(),
            Message::NothingToRollback => "Nothing to rollback".to_string(),
            Message::RollingBack(from, to) => format!("Rolling back from v{} to v{}", from, to),
            Message::RollbackCompleted(version) => format!("Rollback to v{} completed", version),
        };

        write!(f, "{}", text)
    }
}