package tasktracker

import (
	"encoding/json"
	"fmt"
	"os"
	"time"
)

// Task represents a task in our tracker.
// JSON tags are used to control how the struct is serialized/deserialized to/from JSON.
type Task struct {
	ID          int       `json:"id"`
	Description string    `json:"description"`
	Done        bool      `json:"done"`
	CreatedAt   time.Time `json:"created_at"`
}

// TaskManager handles the management and persistence of tasks.
type TaskManager struct {
	FilePath string
}

// NewTaskManager creates a new instance of TaskManager using the provided file path for storage.
func NewTaskManager(filePath string) *TaskManager {
	return &TaskManager{
		FilePath: filePath,
	}
}

// LoadTasks reads and parses tasks from the JSON storage file.
// If the file does not exist, it should return an empty slice and nil error.
func (tm *TaskManager) LoadTasks() ([]Task, error) {
	data, err := os.ReadFile(tm.FilePath)
	if err != nil {
		if os.IsNotExist(err) {
			return []Task{}, nil
		}
		return nil, err
	}
	var tasks []Task
	if err := json.Unmarshal(data, &tasks); err != nil {
		return nil, err
	}
	return tasks, nil
}

// SaveTasks serializes the list of tasks to JSON and writes them to the storage file.
func (tm *TaskManager) SaveTasks(tasks []Task) error {
	data, err := json.MarshalIndent(tasks, "", "  ")
	if err != nil{
		return err
	}
	fmt.Print(tasks)
	os.WriteFile(tm.FilePath, data, 0644)
	return nil
	// TODO: Implement saving tasks to tm.FilePath.
	// Hint: Use json.MarshalIndent (or json.Marshal) to encode the slice of tasks into JSON bytes.
	// Use os.WriteFile to write the bytes to the file.
}

// AddTask creates a new task, assigns it a unique ID (incremented from the max existing ID),
// appends it to the task list, and saves it.
func (tm *TaskManager) AddTask(description string) (Task, error) {
	tasks, err := tm.LoadTasks()
	if err != nil {
		return Task{}, err
	}
	newID := len(tasks) + 1
	newTask := Task{
		ID: newID,
		Description: description,
		Done: false,
		CreatedAt: time.Now(),
	}
	tasks = append(tasks, newTask)
	tm.SaveTasks(tasks)
	return newTask, nil	
	// TODO: Implement adding a task.
	// 1. Load existing tasks.
	// 2. Find the highest current ID and add 1 to get the new task's ID (start with 1 if no tasks exist).
	// 3. Create a new Task struct (set ID, Description, Done = false, CreatedAt = time.Now()).
	// 4. Append it to the slice.
	// 5. Save the updated list.
	// 6. Return the newly created task.
}

// ListTasks returns all tasks.
func (tm *TaskManager) ListTasks() ([]Task, error) {
	tasks, err := tm.LoadTasks()
	if err != nil{
		return nil, err
	}
	
	// TODO: Implement listing tasks.
	// Hint: Just load and return the tasks.
	return tasks, nil
}

// CompleteTask marks the task with the given ID as done and saves the tasks list.
// If the task does not exist, it should return an error.
func (tm *TaskManager) CompleteTask(id int) error {
	tasks , err := tm.LoadTasks()
	if err !=nil{
		return err
	}
	for i,task:= range tasks{
		if task.ID == id{
			tasks[i].Done = true
			tm.SaveTasks(tasks)
			return nil
		}
	}
	return fmt.Errorf("task with ID %d not found", id)
	// TODO: Implement completing a task.
	// 1. Load existing tasks.
	// 2. Find the task with the matching ID.
	// 3. If found, set Done = true. If not found, return an error.
	// 4. Save the updated list.
}

// DeleteTask removes the task with the given ID from the tasks list and saves it.
// If the task does not exist, it should return an error.
func (tm *TaskManager) DeleteTask(id int) error {
	tasks, err := tm.LoadTasks()
	if err !=nil {
		return err
	}
	for i,task := range tasks{
		if task.ID == id{
			tasks = append(tasks[:i], tasks[i+1:]...)
			tm.SaveTasks(tasks)
			return nil
		}
	}
	// TODO: Implement deleting a task.
	// 1. Load existing tasks.
	// 2. Find the task with the matching ID. If not found, return an error.
	// 3. Remove the task from the slice (hint: use append(slice[:i], slice[i+1:]...) to remove index i).
	// 4. Save the updated list.
	return fmt.Errorf("Task ID %d not present",id)
}
