"""Agent task command for managing background agent tasks"""

import json
import os
import time
import uuid
import threading
from concurrent.futures import ThreadPoolExecutor
from dataclasses import dataclass, asdict
from typing import Optional, Dict, Any
from datetime import datetime

from diona.project.cli.commands.base import Command
from diona.project.agent.facade import get_agent_facade


TASK_STATUS_PENDING = "pending"
TASK_STATUS_RUNNING = "running"
TASK_STATUS_COMPLETED = "completed"
TASK_STATUS_FAILED = "failed"
TASK_TYPE_AGENT = "agent"


@dataclass
class AgentTask:
    task_id: str
    task_name: str
    task_type: str
    task_prompt: str
    task_status: str
    task_file_path: str
    task_create_time: str
    task_start_time: Optional[str] = None
    task_end_time: Optional[str] = None
    task_result: Optional[str] = None


class AgentTaskManager:
    def __init__(self):
        self._get_storage()
        self._queue_dir = self._storage.get_path("agent", "tasks/queue", storage_type="user")
        self._finish_dir = self._storage.get_path("agent", "tasks/finish", storage_type="user")
        os.makedirs(self._queue_dir, exist_ok=True)
        os.makedirs(self._finish_dir, exist_ok=True)
        self._executor = ThreadPoolExecutor(max_workers=1)
        self._running_task: Optional[str] = None
        self._running_task_lock = threading.Lock()
    
    def _get_storage(self):
        from diona.project.storage import get_storage_instance
        self._storage = get_storage_instance()
    
    def create_task(self, task_name: str, task_prompt: str) -> AgentTask:
        task_id = str(uuid.uuid4())
        timestamp = datetime.now().isoformat()
        
        task = AgentTask(
            task_id=task_id,
            task_name=task_name,
            task_type=TASK_TYPE_AGENT,
            task_prompt=task_prompt,
            task_status=TASK_STATUS_PENDING,
            task_file_path="",
            task_create_time=timestamp
        )
        
        filename = f"{task.task_create_time.replace(':', '-')}.json"
        task.task_file_path = os.path.join(self._queue_dir, filename)
        
        self._save_task(task)
        return task
    
    def _save_task(self, task: AgentTask):
        with open(task.task_file_path, 'w', encoding='utf-8') as f:
            json.dump(asdict(task), f, ensure_ascii=False, indent=2)
    
    def _load_task(self, file_path: str) -> Optional[AgentTask]:
        if not os.path.exists(file_path):
            return None
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
            return AgentTask(**data)
        except Exception:
            return None
    
    def list_queue_tasks(self) -> list[AgentTask]:
        tasks = []
        if not os.path.exists(self._queue_dir):
            return tasks
        for filename in os.listdir(self._queue_dir):
            if filename.endswith('.json'):
                task = self._load_task(os.path.join(self._queue_dir, filename))
                if task:
                    tasks.append(task)
        return sorted(tasks, key=lambda t: t.task_create_time)
    
    def list_finish_tasks(self) -> list[AgentTask]:
        tasks = []
        if not os.path.exists(self._finish_dir):
            return tasks
        for filename in os.listdir(self._finish_dir):
            if filename.endswith('.json'):
                task = self._load_task(os.path.join(self._finish_dir, filename))
                if task:
                    tasks.append(task)
        return sorted(tasks, key=lambda t: t.task_create_time, reverse=True)
    
    def get_task(self, task_id: str) -> Optional[AgentTask]:
        for task in self.list_queue_tasks() + self.list_finish_tasks():
            if task.task_id == task_id:
                return task
        return None
    
    def delete_queue_task(self, task_id: str) -> bool:
        for task in self.list_queue_tasks():
            if task.task_id == task_id:
                if os.path.exists(task.task_file_path):
                    os.remove(task.task_file_path)
                return True
        return False
    
    def delete_finish_task(self, task_id: str) -> bool:
        for task in self.list_finish_tasks():
            if task.task_id == task_id:
                if os.path.exists(task.task_file_path):
                    os.remove(task.task_file_path)
                return True
        return False
    
    def submit_task(self, task: AgentTask):
        self._executor.submit(self._execute_task, task)
    
    def _execute_task(self, task: AgentTask):
        with self._running_task_lock:
            self._running_task = task.task_id
        
        task.task_status = TASK_STATUS_RUNNING
        task.task_start_time = datetime.now().isoformat()
        self._save_task(task)
        
        try:
            facade = get_agent_facade()
            result = facade.run(task.task_prompt, use_session=False)
            
            task.task_status = TASK_STATUS_COMPLETED
            task.task_result = result
        except Exception as e:
            task.task_status = TASK_STATUS_FAILED
            task.task_result = f"Error: {str(e)}"
        
        task.task_end_time = datetime.now().isoformat()
        
        finish_filename = f"{task.task_create_time.replace(':', '-')}"
        finish_path = os.path.join(self._finish_dir, finish_filename + ".json")
        task.task_file_path = finish_path
        self._save_task(task)
        
        queue_path = os.path.join(self._queue_dir, f"{task.task_create_time.replace(':', '-')}.json")
        if os.path.exists(queue_path):
            os.remove(queue_path)
        
        with self._running_task_lock:
            self._running_task = None
    
    def get_running_task_id(self) -> Optional[str]:
        with self._running_task_lock:
            return self._running_task


_task_manager: Optional[AgentTaskManager] = None


def get_task_manager() -> AgentTaskManager:
    global _task_manager
    if _task_manager is None:
        _task_manager = AgentTaskManager()
    return _task_manager


class AgentTaskCommand(Command):
    name = "task"
    description = "Manage agent background tasks"
    
    def execute(self, args):
        if not args:
            return self._show_help()
        
        action = args[0]
        
        if action == "-h" or action == "--help":
            return self._show_help()
        elif action == "add":
            return self._add_task(args[1:])
        elif action == "list":
            return self._list_tasks()
        elif action == "delete":
            return self._delete_task(args[1:])
        elif action == "show":
            return self._show_task_result(args[1:])
        elif action == "running":
            return self._show_running_task()
        else:
            print(f"Unknown action: {action}")
            return self._show_help()
    
    def _show_help(self):
        help_text = """Usage: task <action> [options]

Actions:
  add <task_name> <task_prompt>    Create and submit a new agent task
  list                              List all tasks (queue and finished)
  delete <task_id>                  Delete a task (from queue or finished)
  show <task_id>                   Show task result
  running                           Show currently running task

Examples:
  task add "my task" "Hello, how are you?"
  task list
  task delete 12345678
  task show 12345678
  task running"""
        print(help_text)
        return False
    
    def _add_task(self, args):
        if len(args) < 2:
            print("Usage: task add <task_name> <task_prompt>")
            return False
        
        task_name = args[0]
        task_prompt = " ".join(args[1:])
        
        task_mgr = get_task_manager()
        task = task_mgr.create_task(task_name, task_prompt)
        
        time.sleep(0.1)
        task_mgr.submit_task(task)
        
        print(f"Task created: {task.task_id}")
        print(f"Task name: {task.task_name}")
        print(f"Status: {task.task_status}")
        
        return False
    
    def _list_tasks(self):
        task_mgr = get_task_manager()
        
        queue_tasks = task_mgr.list_queue_tasks()
        finish_tasks = task_mgr.list_finish_tasks()
        running_id = task_mgr.get_running_task_id()
        
        print("=== Queue Tasks ===")
        if queue_tasks:
            for task in queue_tasks:
                status = "RUNNING" if task.task_id == running_id else task.task_status
                print(f"  [{status}] {task.task_name} ({task.task_id})")
        else:
            print("  (empty)")
        
        print("\n=== Finished Tasks ===")
        if finish_tasks:
            for task in finish_tasks:
                print(f"  [{task.task_status}] {task.task_name} ({task.task_id})")
        else:
            print("  (empty)")
        
        return False
    
    def _delete_task(self, args):
        if not args:
            print("Usage: task delete <task_id>")
            return False
        
        task_id = args[0]
        
        task_mgr = get_task_manager()
        
        if task_mgr.delete_queue_task(task_id):
            print(f"Deleted queue task: {task_id}")
        elif task_mgr.delete_finish_task(task_id):
            print(f"Deleted finished task: {task_id}")
        else:
            print(f"Task not found: {task_id}")
        
        return False
    
    def _show_task_result(self, args):
        if not args:
            print("Usage: task show <task_id>")
            return False
        
        task_id = args[0]
        
        task_mgr = get_task_manager()
        task = task_mgr.get_task(task_id)
        
        if not task:
            print(f"Task not found: {task_id}")
            return False
        
        print(f"\n=== Task: {task.task_name} ===")
        print(f"ID: {task.task_id}")
        print(f"Status: {task.task_status}")
        print(f"Created: {task.task_create_time}")
        
        if task.task_start_time:
            print(f"Started: {task.task_start_time}")
        if task.task_end_time:
            print(f"Finished: {task.task_end_time}")
        
        print(f"\n--- Prompt ---")
        print(task.task_prompt)
        
        if task.task_result:
            print(f"\n--- Result ---")
            print(task.task_result)
        
        return False
    
    def _show_running_task(self):
        task_mgr = get_task_manager()
        running_id = task_mgr.get_running_task_id()
        
        if running_id:
            task = task_mgr.get_task(running_id)
            if task:
                print(f"Running: {task.task_name} ({task.task_id})")
                print(f"Prompt: {task.task_prompt[:100]}...")
            else:
                print("No task running")
        else:
            print("No task running")
        
        return False
