File size: 7,410 Bytes
99a2380
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Main CLI interface for Todo application."""

import sys
from datetime import datetime

from ..models.todo import TodoStatus
from ..services.todo_service import (
    AlreadyCompletedError,
    InvalidTitleError,
    TodoNotFoundError,
    TodoService,
)


# =============================================================================
# CLI Helper Functions
# =============================================================================


def format_todo(todo) -> str:
    """Format todo for display.

    Args:
        todo: Todo object to format

    Returns:
        Formatted string representation
    """
    description = todo.description if todo.description else "No description"
    created_str = todo.created_at.strftime("%Y-%m-%d %H:%M:%S")
    return (
        f"ID: {todo.id}\n"
        f"Title: {todo.title}\n"
        f"Description: {description}\n"
        f"Status: {todo.status.value}\n"
        f"Created: {created_str}"
    )


def format_todo_list_item(todo) -> str:
    """Format todo for list display.

    Args:
        todo: Todo object to format

    Returns:
        Formatted string for list view
    """
    return f"ID: {todo.id} | Title: {todo.title} | Status: {todo.status.value}"


# =============================================================================
# CLI Commands
# =============================================================================


def cmd_create_todo(service: TodoService) -> None:
    """Create a new todo.

    Args:
        service: TodoService instance
    """
    print("\n=== Create Todo ===")
    title = input("Enter title (required): ").strip()

    if not title:
        print("\nERROR: Title cannot be empty.")
        return

    description = input("Enter description (optional, press Enter to skip): ").strip()
    description = description if description else None

    try:
        todo = service.create_todo(title, description)
        print("\n=== Todo Created Successfully ===")
        print(format_todo(todo))
    except (InvalidTitleError, Exception) as e:
        print(f"\nERROR: {e}")


def cmd_list_todos(service: TodoService) -> None:
    """List all todos.

    Args:
        service: TodoService instance
    """
    print("\n=== Your Todos ===")
    todos = service.list_todos()

    if not todos:
        print("\nNo todos found.")
        return

    for todo in todos:
        print(format_todo_list_item(todo))


def cmd_view_todo(service: TodoService) -> None:
    """View details of a specific todo.

    Args:
        service: TodoService instance
    """
    print("\n=== View Todo ===")
    todo_id_str = input("Enter todo ID: ").strip()

    try:
        todo_id = int(todo_id_str)
    except ValueError:
        print("\n❌ Error: Todo ID must be a number.")
        return

    try:
        todo = service.get_todo_by_id(todo_id)
        print("\n=== Todo Details ===")
        print(format_todo(todo))
    except TodoNotFoundError as e:
        print(f"\nERROR: {e}")


def cmd_update_todo(service: TodoService) -> None:
    """Update an existing todo.

    Args:
        service: TodoService instance
    """
    print("\n=== Update Todo ===")
    todo_id_str = input("Enter todo ID: ").strip()

    try:
        todo_id = int(todo_id_str)
    except ValueError:
        print("\n❌ Error: Todo ID must be a number.")
        return

    # First, retrieve the todo to show current values
    try:
        current_todo = service.get_todo_by_id(todo_id)
    except TodoNotFoundError as e:
        print(f"\nERROR: {e}")
        return

    print(f"\nCurrent title: {current_todo.title}")
    new_title = input("Enter new title (press Enter to keep current): ").strip()

    print(f"\nCurrent description: {current_todo.description or 'No description'}")
    new_description = input("Enter new description (press Enter to keep current): ").strip()
    new_description = new_description if new_description else None

    # If user provided empty input for both, nothing to update
    if not new_title and new_description is None:
        print("\nNo changes provided.")
        return

    try:
        updated_todo = service.update_todo(
            todo_id,
            title=new_title if new_title else None,
            description=new_description,
        )
        print("\n✅ Todo updated successfully!")
        print(format_todo(updated_todo))
    except (TodoNotFoundError, InvalidTitleError, Exception) as e:
        print(f"\nERROR: {e}")


def cmd_complete_todo(service: TodoService) -> None:
    """Mark a todo as completed.

    Args:
        service: TodoService instance
    """
    print("\n=== Complete Todo ===")
    todo_id_str = input("Enter todo ID: ").strip()

    try:
        todo_id = int(todo_id_str)
    except ValueError:
        print("\n❌ Error: Todo ID must be a number.")
        return

    try:
        todo = service.complete_todo(todo_id)
        print("\n✅ Todo marked as completed!")
        print(format_todo(todo))
    except AlreadyCompletedError as e:
        print(f"\nERROR: {e}")
    except TodoNotFoundError as e:
        print(f"\nERROR: {e}")


def cmd_delete_todo(service: TodoService) -> None:
    """Delete a todo.

    Args:
        service: TodoService instance
    """
    print("\n=== Delete Todo ===")
    todo_id_str = input("Enter todo ID: ").strip()

    try:
        todo_id = int(todo_id_str)
    except ValueError:
        print("\n❌ Error: Todo ID must be a number.")
        return

    try:
        service.delete_todo(todo_id)
        print(f"\n✅ Todo {todo_id} deleted successfully!")
    except TodoNotFoundError as e:
        print(f"\nERROR: {e}")


# =============================================================================
# Main Menu
# =============================================================================


def main_menu(service: TodoService) -> None:
    """Display main menu and handle user choices.

    Args:
        service: TodoService instance
    """
    while True:
        print("\n" + "=" * 40)
        print("=== Todo App ===")
        print("=" * 40)
        print("1. Create Todo")
        print("2. List Todos")
        print("3. View Todo")
        print("4. Update Todo")
        print("5. Complete Todo")
        print("6. Delete Todo")
        print("7. Exit")
        print("=" * 40)

        choice = input("\nEnter choice (1-7): ").strip()

        if choice == "1":
            cmd_create_todo(service)
        elif choice == "2":
            cmd_list_todos(service)
        elif choice == "3":
            cmd_view_todo(service)
        elif choice == "4":
            cmd_update_todo(service)
        elif choice == "5":
            cmd_complete_todo(service)
        elif choice == "6":
            cmd_delete_todo(service)
        elif choice == "7":
            print("\n=== Goodbye! ===")
            sys.exit(0)
        else:
            print("\nERROR: Invalid choice. Please enter a number between 1 and 7.")


# =============================================================================
# Entry Point
# =============================================================================


def main() -> None:
    """Main entry point for the CLI application."""
    print("Welcome to Phase-1 In-Memory Todo App!")
    print("All data is stored in memory and will be lost on exit.\n")

    service = TodoService()
    main_menu(service)


if __name__ == "__main__":
    main()