import datetime
import json
import uuid
from dataclasses import dataclass
from pathlib import Path
from typing import Dict, List

import pytz
from smolagents import tool


@dataclass
class Task:
    id: str = None
    completed: bool = False
    description: str = ""
    last_updated: str = ""

    def __post_init__(self):
        if self.id is None:
            self.id = str(uuid.uuid4())

    def to_dict(self) -> Dict:
        return {
            "id": self.id,
            "completed": self.completed,
            "description": self.description,
            "last_updated": self.last_updated,
        }


class TodoManager:
    def __init__(self, filepath: str = "todo.jsonl"):
        self.filepath = Path(filepath)
        if not self.filepath.exists():
            self.filepath.write_text("")

    def _read_tasks(self) -> List[Task]:
        if not self.filepath.exists():
            return []

        try:
            with self.filepath.open("r", encoding="utf-8") as file:
                data = [json.loads(line) for line in file if line.strip()]

            return [
                Task(
                    description=item.get("description", item.get("task", "")),
                    completed=item.get("completed", item.get("status") == "āœ…"),
                    last_updated=item["last_updated"],
                    id=item.get("id"),
                )
                for item in data
            ]
        except json.JSONDecodeError:
            return []

    def _save_tasks(self, tasks: List[Task]):
        with self.filepath.open("w") as file:
            for task in tasks:
                file.write(json.dumps(task.to_dict()) + "\n")


@tool
def get_current_time_in_timezone(timezone: str) -> str:
    """A tool that fetches the current local time in a specified timezone.
    Args:
        timezone: A string representing a valid timezone (e.g., 'America/New_York').
    """
    try:
        tz = pytz.timezone(timezone)
        local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
        return f"The current local time in {timezone} is: {local_time}"
    except Exception as e:
        return f"Error fetching time for timezone '{timezone}': {str(e)}"


@tool
def get_todays_tasks() -> str:
    """List all tasks with their status and details.
    Args:
        None
    Returns:
        A formatted string containing all tasks with their status and IDs.
    """
    manager = TodoManager("./todo.jsonl")
    tasks = manager._read_tasks()

    if not tasks:
        return "No tasks found"

    pending = [t for t in tasks if not t.completed]
    completed = [t for t in tasks if t.completed]  # Uncomment this to show all tasks

    output = [f"šŸ“… Tasks Report for {datetime.date.today()}"]
    output.append("\nšŸ”“ Pending Tasks:")
    output.extend(f"[{t.id[:8]}] {t.description}" for t in pending)
    output.append("\nāœ… Completed Tasks:")  # Show both pending and completed tasks
    output.extend(f"[{t.id[:8]}] {t.description}" for t in completed)
    output.append(f"\nTotal: {len(pending)} pending, {len(completed)} completed")

    return "\n".join(output)


@tool
def update_task_status(task_id: str) -> str:
    """Toggle a task's completion status between complete and pending.
    Args:
        task_id: First 8 characters of the task's UUID (e.g., '65118069' from '65118069-b2a4-4ea3-b8e9-d7921381cbfc').
                You can find task IDs in square brackets when listing tasks.
    Returns:
        Success message with task details if found and updated.
        Error message if task not found or invalid input.
    Examples:
        > update_task_status('65118069')
        "āœ… Task [65118069] marked as complete: Repair my computer"
        > update_task_status('65118069')
        "āœ… Task [65118069] marked as pending: Repair my computer"
    """
    # Validate task_id format
    if not task_id or not isinstance(task_id, str) or len(task_id) < 1:
        return "āŒ Please provide a valid task ID"

    try:
        manager = TodoManager("./todo.jsonl")
        tasks = manager._read_tasks()

        if not tasks:
            return "āŒ No tasks found in the todo list"

        # Find and update the task
        for task in tasks:
            if task.id.startswith(task_id):
                task.completed = not task.completed
                task.last_updated = datetime.date.today().strftime("%Y-%m-%d")
                manager._save_tasks(tasks)
                return f"āœ… Task [{task_id}] marked as {'complete' if task.completed else 'pending'}: {task.description}"

        return f"āŒ No task found with ID '{task_id}'"

    except (json.JSONDecodeError, IOError) as e:
        return f"āŒ Error accessing todo list: {str(e)}"
    except Exception as e:
        return f"āŒ Unexpected error: {str(e)}"


@tool
def add_task(description: str) -> str:
    """Add a new task to the todo list.
    Args:
        description: The text description of the task to add.
    Returns:
        A confirmation message indicating the task was added.
    """
    manager = TodoManager("./todo.jsonl")
    tasks = manager._read_tasks()

    new_task = Task(
        description=description,
        completed=False,
        last_updated=datetime.date.today().strftime("%Y-%m-%d"),
    )

    tasks.append(new_task)
    manager._save_tasks(tasks)
    return f"āœ… Added new task: {description}"