from django.shortcuts import render, redirect, get_object_or_404
from django.http import JsonResponse
from django.views.decorators.http import require_POST
import json
import logging
from .models import Article, TodoItem, Conversation, Message
from .forms import TodoItemForm
import time
from ai.local_ai_api import LocalAIApi

# Get an instance of a logger
logger = logging.getLogger(__name__)

def index(request):
    if request.method == 'POST':
        form = TodoItemForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('core:index')
    else:
        form = TodoItemForm()
    
    todo_list = TodoItem.objects.all().order_by('-created_at')
    articles = Article.objects.all()
    
    context = {
        'articles': articles,
        'todo_list': todo_list,
        'form': form,
        'timestamp': int(time.time()),
    }
    return render(request, "core/index.html", context)

def kanban_board(request):
    tasks = TodoItem.objects.all().order_by('created_at')
    tasks_by_status = {
        status_value: list(filter(lambda t: t.status == status_value, tasks))
        for status_value, status_display in TodoItem.STATUS_CHOICES
    }

    context = {
        'tasks_by_status': tasks_by_status,
        'status_choices': TodoItem.STATUS_CHOICES,
        'timestamp': int(time.time()),
    }
    return render(request, "core/kanban.html", context)

def article_detail(request, article_id):
    article = Article.objects.get(pk=article_id)
    return render(request, "core/article_detail.html", {"article": article})

@require_POST
def update_task_status(request):
    try:
        data = json.loads(request.body)
        task_id = data.get('task_id')
        new_status = data.get('new_status')

        task = get_object_or_404(TodoItem, id=task_id)
        task.status = new_status
        task.save()

        return JsonResponse({'success': True})
    except (json.JSONDecodeError, TypeError, ValueError) as e:
        return JsonResponse({'success': False, 'error': str(e)}, status=400)


@require_POST
def delete_task(request, task_id):
    task = get_object_or_404(TodoItem, id=task_id)
    task.delete()
    
    # Redirect to the previous page or a default URL
    referer = request.META.get('HTTP_REFERER')
    if referer:
        return redirect(referer)
    return redirect('core:index')

@require_POST
def cleanup_tasks(request):
    TodoItem.objects.all().delete()
    return redirect('core:index')

def execute_command(command_data):
    command_name = command_data.get('name')
    args = command_data.get('args', {})
    logger.info(f"Executing command: {command_name} with args: {args}")

    try:
        if command_name == 'send_message':
            message = args.get('message')
            if not message:
                logger.error("Command 'send_message' failed: 'message' is a required argument.")
                return "[SYSTEM] Error: 'message' is a required argument for send_message."
            return message

        elif command_name == 'add_task':
            title = args.get('title')
            if not title:
                logger.error("Command 'add_task' failed: 'title' is a required argument.")
                return "[SYSTEM] Error: 'title' is a required argument for add_task."
            
            new_task = TodoItem.objects.create(
                title=title,
                description=args.get('description', ''),
                status=args.get('status', 'todo')
            )
            logger.info(f"Command 'add_task' executed successfully. New task ID: {new_task.id}")
            return f"[SYSTEM] Command 'add_task' executed successfully. New task ID: {new_task.id}"

        elif command_name == 'edit_task':
            task_id = args.get('task_id')
            if not task_id:
                logger.error("Command 'edit_task' failed: 'task_id' is a required argument.")
                return "[SYSTEM] Error: 'task_id' is a required argument for edit_task."

            task = get_object_or_404(TodoItem, id=task_id)
            
            if 'title' in args:
                task.title = args['title']
            if 'description' in args:
                task.description = args['description']
            if 'status' in args:
                task.status = args['status']
            
            task.save()
            logger.info(f"Command 'edit_task' for task ID {task_id} executed successfully.")
            return f"[SYSTEM] Command 'edit_task' for task ID {task_id} executed successfully."

        elif command_name == 'delete_task':
            task_id = args.get('task_id')
            if not task_id:
                logger.error("Command 'delete_task' failed: 'task_id' is a required argument.")
                return "[SYSTEM] Error: 'task_id' is a required argument for delete_task."

            task = get_object_or_404(TodoItem, id=task_id)
            task.delete()
            logger.info(f"Command 'delete_task' for task ID {task_id} executed successfully.")
            return f"[SYSTEM] Command 'delete_task' for task ID {task_id} executed successfully."

        else:
            logger.warning(f"Unknown command received: '{command_name}'")
            return f"[SYSTEM] Error: Unknown command '{command_name}'."
    except Exception as e:
        logger.error(f"Error executing command '{command_name}': {e}", exc_info=True)
        return f"[SYSTEM] Error executing command '{command_name}': {e}"

def chat_view(request, conversation_id=None):
    if request.method == 'POST':
        if 'title' in request.POST:
            title = request.POST.get('title', 'New Conversation')
            conversation = Conversation.objects.create(title=title)
            return redirect('core:chat_detail', conversation_id=conversation.id)
        
        elif 'text' in request.POST and conversation_id:
            text = request.POST.get('text')
            selected_conversation = get_object_or_404(Conversation, id=conversation_id)
            
            if text:
                command_name = None  # Initialize command_name
                Message.objects.create(conversation=selected_conversation, content=text, sender='user')
                
                history = []
                for msg in selected_conversation.messages.order_by('created_at'):
                    role = msg.sender
                    if role == 'ai':
                        role = 'assistant'
                    elif role == 'system':
                        role = 'user'
                    history.append({"role": role, "content": msg.content})
                
                try:
                    system_message = {
                        "role": "system",
                        "content": '''You are a project management assistant. To communicate with the user, you MUST use the `send_message` command.

**Commands must be in a specific JSON format.** Your response must be a JSON object with the following structure:

```json
{
  "command": {
    "name": "command_name",
    "args": {
      "arg1": "value1",
      "arg2": "value2"
    }
  }
}
```

**Available Commands:**

*   `send_message`: Sends a message to the user. **USE THIS FOR ALL CONVERSATIONAL RESPONSES.**
    *   `args`:
        *   `message` (string, required): The message to send to the user.
*   `add_task`: Adds a new task.
    *   `args`:
        *   `title` (string, required): The title of the task.
        *   `description` (string, optional): The description of the task.
        *   `status` (string, optional, default: 'todo'): The status of the task. Can be 'todo', 'inprogress', 'done', 'blocked'.
*   `edit_task`: Edits an existing task.
    *   `args`:
        *   `task_id` (integer, required): The ID of the task to edit.
        *   `title` (string, optional): The new title.
        *   `description` (string, optional): The new description.
        *   `status` (string, optional): The new status.
*   `delete_task`: Deletes a task.
    *   `args`:
        *   `task_id` (integer, required): The ID of the task to delete.

**Execution Loop:**

1.  You issue a command.
2.  The system executes it.
3.  The system returns a result message to you, like `[SYSTEM] Command 'add_task' executed successfully. New task ID: 5`.
4.  You can then issue another command.

**VERY IMPORTANT:**
- To talk to the user, you MUST use the `send_message` command.
- ONLY use other commands if the user explicitly asks you to `add`, `edit`, or `delete` tasks.

**Examples:**

*   **User:** "Hi, how are you?"
    *   **Correct AI Response:**
        ```json
        {
          "command": {
            "name": "send_message",
            "args": {
              "message": "I'm doing great, thanks for asking! How can I help you with your tasks today?"
            }
          }
        }
        ```
*   **User:** "add a new task to buy milk"
    *   **Correct AI Response:**
        ```json
        {
          "command": {
            "name": "add_task",
            "args": {
              "title": "buy milk"
            }
          }
        }
        ```

**IMPORTANT:** Do not wrap the JSON command in markdown backticks or any other text. The entire response must be the JSON object.'''
                    }

                    tasks = TodoItem.objects.all().order_by('created_at')
                    task_list_str = "\n".join([
                        f"- ID {task.id}: {task.title} (Status: {task.get_status_display()}, Tags: {task.tags or 'None'})" for task in tasks
                    ])
                    
                    tasks_context = {
                        "role": "system",
                        "content": f"Here is the current list of tasks:\n{task_list_str}"
                    }

                    logger.info("Sending request to AI...")
                    response = LocalAIApi.create_response({
                        "input": [
                            system_message,
                            tasks_context,
                        ] + history,
                        "text": {"format": {"type": "json_object"}},
                    })
                    
                    if not response.get("success"):
                        logger.error(f"AI API request failed with status {response.get('status')}. Full error: {response.get('response')}")
                        ai_text = "I couldn't process that. Please try again."
                        Message.objects.create(conversation=selected_conversation, content=ai_text, sender='ai')
                    else:
                        logger.info(f"AI raw response: {response}")
                        ai_text = LocalAIApi.extract_text(response)
                        logger.info(f"Extracted AI text: {ai_text}")

                        if not ai_text:
                            logger.warning("AI response was empty.")
                            ai_text = "I couldn't process that. Please try again."
                            Message.objects.create(conversation=selected_conversation, content=ai_text, sender='ai')
                        else:
                            ai_message_content = ai_text
                            sender = 'ai'
                            
                            try:
                                command_json = json.loads(ai_text)
                                if 'command' in command_json:
                                    command_name = command_json.get('command', {}).get('name')
                                    command_result = execute_command(command_json['command'])
                                    
                                    ai_message_content = command_result
                                    sender = 'ai' if command_name == 'send_message' else 'system'
                            except (json.JSONDecodeError, TypeError):
                                # Not a JSON command, treat as a raw message.
                                pass

                            Message.objects.create(conversation=selected_conversation, content=ai_message_content, sender=sender)

                except Exception as e:
                    logger.error(f"An unexpected error occurred: {e}", exc_info=True)
                    ai_text = f"An error occurred: {str(e)}"
                    Message.objects.create(conversation=selected_conversation, content=ai_text, sender='ai')

                return redirect('core:chat_detail', conversation_id=conversation_id)

    conversations = Conversation.objects.order_by('-created_at')
    selected_conversation = get_object_or_404(Conversation, id=conversation_id) if conversation_id else None

    return render(request, 'core/chat.html', {
        'conversation_list': conversations,
        'selected_conversation': selected_conversation,
        'timestamp': int(time.time()),
    })
