# src/gollm/project_management/todo_manager.py
import json
import os
import re
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional


@dataclass
class Task:
    id: str
    title: str
    description: str
    priority: str
    status: str = "pending"
    created_at: str = ""
    estimated_effort: str = ""
    related_files: List[str] = None
    approach_suggestions: List[str] = None

    def __post_init__(self):
        if self.related_files is None:
            self.related_files = []
        if self.approach_suggestions is None:
            self.approach_suggestions = []


class TodoManager:
    """Zarządza listą TODO i automatycznie tworzy zadania z naruszeń"""

    def __init__(self, config):
        self.config = config
        self.todo_file = Path(config.project_management.todo_file)
        self.tasks = []
        self._load_tasks()

    def _load_tasks(self):
        """Ładuje zadania z pliku TODO.md"""
        if not self.todo_file.exists():
            self._create_default_todo_file()
            return

        with open(self.todo_file, "r", encoding="utf-8") as f:
            content = f.read()

        self.tasks = self._parse_todo_content(content)

    def _create_default_todo_file(self):
        """Tworzy domyślny plik TODO.md"""
        template = """# TODO List - Project Tasks

## 🔴 HIGH Priority

## 🟡 MEDIUM Priority

## 🟢 LOW Priority

---
*This file is automatically managed by goLLM*
"""
        with open(self.todo_file, "w", encoding="utf-8") as f:
            f.write(template)

    def _parse_todo_content(self, content: str) -> List[Task]:
        """Parsuje zawartość pliku TODO i zwraca listę zadań"""
        tasks = []
        current_priority = "LOW"

        lines = content.split("\n")
        i = 0

        while i < len(lines):
            line = lines[i].strip()

            # Sprawdź sekcję priorytetów
            if "🔴" in line or "HIGH" in line.upper():
                current_priority = "HIGH"
            elif "🟡" in line or "MEDIUM" in line.upper():
                current_priority = "MEDIUM"
            elif "🟢" in line or "LOW" in line.upper():
                current_priority = "LOW"

            # Sprawdź czy to zadanie
            task_match = re.match(r"- \[([ x])\] \*\*(.*?)\*\*", line)
            if task_match:
                status = "completed" if task_match.group(1) == "x" else "pending"
                title = task_match.group(2)

                # Zbierz szczegóły zadania
                description_lines = []
                i += 1
                while i < len(lines) and lines[i].strip().startswith("-"):
                    description_lines.append(lines[i].strip()[1:].strip())
                    i += 1

                task = Task(
                    id=f"task-{len(tasks)+1:03d}",
                    title=title,
                    description="\n".join(description_lines),
                    priority=current_priority,
                    status=status,
                )
                tasks.append(task)
                continue

            i += 1

        return tasks

    def add_task_from_violation(
        self, violation_type: str, details: Dict[str, Any]
    ) -> Task:
        """Tworzy zadanie na podstawie naruszenia jakości kodu, jeśli nie istnieje już podobne zadanie"""
        # Sprawdź czy istnieje już podobne zadanie
        file_path = details.get("file_path", "")
        issue_message = details.get("message", "")

        # Szukaj istniejącego zadania z tym samym typem naruszenia i plikiem
        for task in self.tasks:
            if (
                task.status == "pending"
                and violation_type in task.title.lower().replace(" ", "_")
                and file_path in task.related_files
            ):
                return task  # Zwróć istniejące zadanie zamiast tworzyć nowe

        # Jeśli nie znaleziono istniejącego zadania, utwórz nowe
        priority_map = {
            "file_too_long": "HIGH",
            "function_too_long": "MEDIUM",
            "forbidden_print": "MEDIUM",
            "missing_docstring": "LOW",
            "high_complexity": "HIGH",
            "too_many_parameters": "MEDIUM",
        }

        suggestion_map = {
            "file_too_long": [
                "Split into smaller modules",
                "Extract classes to separate files",
            ],
            "function_too_long": [
                "Break into smaller functions",
                "Extract helper methods",
            ],
            "forbidden_print": ["Replace with logging", "Use proper logging levels"],
            "missing_docstring": [
                "Add Google-style docstring",
                "Document parameters and return values",
            ],
            "high_complexity": [
                "Simplify logic",
                "Extract sub-functions",
                "Use early returns",
            ],
            "too_many_parameters": ["Use dataclass", "Create configuration object"],
        }

        priority = priority_map.get(violation_type, "MEDIUM")
        suggestions = suggestion_map.get(violation_type, [])

        task = Task(
            id=f"gollm-{datetime.now().strftime('%Y%m%d%H%M%S')}-{len(self.tasks)+1:03d}",
            title=f"Fix {violation_type.replace('_', ' ')} in {file_path or 'unknown'}",
            description=f"Location: {file_path}:{details.get('line_number', 0)}\n"
            + f"Issue: {issue_message or 'No description'}\n"
            + f"Auto-fix available: {'Yes' if details.get('auto_fix_available') else 'No'}",
            priority=priority,
            created_at=datetime.now().isoformat(),
            estimated_effort=self._estimate_effort(violation_type),
            related_files=[file_path] if file_path else [],
            approach_suggestions=suggestions,
        )

        self.tasks.append(task)
        self._save_tasks()
        return task

    def _estimate_effort(self, violation_type: str) -> str:
        """Szacuje czas potrzebny na naprawę"""
        effort_map = {
            "file_too_long": "2-4 hours",
            "function_too_long": "30-60 minutes",
            "forbidden_print": "5-10 minutes",
            "missing_docstring": "15-30 minutes",
            "high_complexity": "1-3 hours",
            "too_many_parameters": "45-90 minutes",
            "code_generation": "15-60 minutes",
            "code_review": "10-30 minutes",
        }
        return effort_map.get(violation_type, "30 minutes")

    def get_next_task(self) -> Optional[Dict[str, Any]]:
        """Zwraca następne zadanie do wykonania"""
        pending_tasks = [t for t in self.tasks if t.status == "pending"]

        if not pending_tasks:
            return None

        # Sortuj według priorytetu
        priority_order = {"HIGH": 0, "MEDIUM": 1, "LOW": 2}
        sorted_tasks = sorted(
            pending_tasks, key=lambda t: priority_order.get(t.priority, 3)
        )

        next_task = sorted_tasks[0]
        return {
            "id": next_task.id,
            "title": next_task.title,
            "description": next_task.description,
            "priority": next_task.priority,
            "estimated_effort": next_task.estimated_effort,
            "related_files": next_task.related_files,
            "approach_suggestions": next_task.approach_suggestions,
        }

    def complete_task(self, task_id: str, changelog_manager=None):
        """Oznacza zadanie jako ukończone i dodaje wpis do changelog"""
        for task in self.tasks:
            if task.id == task_id and task.status != "completed":
                task.status = "completed"

                # Dodaj wpis do changelog jeśli podano manager
                if changelog_manager and hasattr(changelog_manager, "record_change"):
                    change_details = {
                        "description": f"Completed task: {task.title}",
                        "files": task.related_files,
                        "quality_delta": 5,  # Przykładowa wartość poprawy jakości
                    }
                    changelog_manager.record_change("task_completed", change_details)

                self._save_tasks()
                return True
        return False

    def get_stats(self) -> Dict[str, int]:
        """Zwraca statystyki zadań"""
        pending = [t for t in self.tasks if t.status == "pending"]
        completed = [t for t in self.tasks if t.status == "completed"]
        high_priority = [
            t for t in self.tasks if t.status == "pending" and t.priority == "HIGH"
        ]
        code_gen_tasks = [t for t in self.tasks if t.id.startswith("gen-")]

        return {
            "total": len(self.tasks),
            "pending": len(pending),
            "completed": len(completed),
            "high_priority": len(high_priority),
            "code_generation_tasks": len(code_gen_tasks),
        }

    def _save_tasks(self):
        """Zapisuje zadania do pliku TODO.md"""
        content = self._generate_todo_content()
        with open(self.todo_file, "w", encoding="utf-8") as f:
            f.write(content)

    def _format_description(self, description: str, context: Dict[str, Any]) -> str:
        """Formatuje opis zadania w czytelny sposób"""
        lines = [f"{description}"]

        # Dodaj kontekst w formie punktowanej listy
        if context:
            lines.append("\n**Context:**")

            # Obsłuż różne typy kontekstu
            if "request" in context:
                lines.append(f"- Task: {context['request']}")

            if "context" in context and isinstance(context["context"], dict):
                ctx = context["context"]
                if "is_critical" in ctx:
                    lines.append(
                        f"- Priority: {'🔴 HIGH' if ctx['is_critical'] else '🟡 MEDIUM'}"
                    )
                if "related_files" in ctx and ctx["related_files"]:
                    files = ", ".join(f"`{f}`" for f in ctx["related_files"] if f)
                    lines.append(f"- Related files: {files}")

        return "\n".join(lines)

    def add_code_generation_task(
        self, description: str, context: Dict[str, Any]
    ) -> Task:
        """Dodaje zadanie generowania kodu"""
        task = Task(
            id=f"gen-{datetime.now().strftime('%Y%m%d%H%M%S')}",
            title=f"[CodeGen] {description[:50]}",
            description=self._format_description(description, context),
            priority="HIGH" if context.get("is_critical") else "MEDIUM",
            created_at=datetime.now().isoformat(),
            estimated_effort=self._estimate_effort("code_generation"),
            related_files=context.get("related_files", []),
        )
        self.tasks.append(task)
        self._save_tasks()
        return task

    def _format_result_details(self, result: Dict[str, Any]) -> str:
        """Formatuje szczegóły wyniku w czytelny sposób"""
        lines = []

        if "output_file" in result and result["output_file"] != "unknown.py":
            lines.append(f"- 📄 **Output file:** `{result['output_file']}`")

        if "quality_score" in result:
            score = result["quality_score"]
            emoji = "🟢" if score >= 90 else "🟡" if score >= 70 else "🔴"
            lines.append(f"- {emoji} **Code quality:** {score}/100")

        if "violations" in result and result["violations"]:
            lines.append("\n**Fixed issues:**")
            for violation in result["violations"]:
                v_type = violation.get("type", "Issue")
                v_msg = violation.get("message", "No details")
                lines.append(f"  - {v_type}: {v_msg}")

        return "\n".join(lines)

    def update_code_generation_task(self, task_id: str, result: Dict[str, Any]):
        """Aktualizuje zadanie po wygenerowaniu kodu"""
        for task in self.tasks:
            if task.id == task_id:
                result_details = self._format_result_details(result)
                if result_details:
                    task.description += "\n\n" + result_details

                task.status = "completed"
                self._save_tasks()
                return True
        return False

    def _generate_todo_content(self) -> str:
        """Generuje zawartość pliku TODO.md z tylko nieukończonymi zadaniami"""
        # Filtruj tylko nieukończone zadania
        pending_tasks = [t for t in self.tasks if t.status != "completed"]
        stats = self.get_stats()

        content = f"# 📋 TODO List - Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
        content += f"**Status:** {stats['completed']}✓ {len(pending_tasks)}⏳ • "

        # Policz zadania wg priorytetów
        priority_counts = {
            "HIGH": len([t for t in pending_tasks if t.priority == "HIGH"]),
            "MEDIUM": len([t for t in pending_tasks if t.priority == "MEDIUM"]),
            "LOW": len([t for t in pending_tasks if t.priority == "LOW"]),
        }

        content += f"**Priority:** {priority_counts['HIGH']}🔴 {priority_counts['MEDIUM']}🟡 {priority_counts['LOW']}🟢 • "
        content += f"**Code Gen:** {stats['code_generation_tasks']}🔄\n\n"

        # Grupuj zadania według priorytetu (tylko nieukończone)
        for priority, emoji in [("HIGH", "🔴"), ("MEDIUM", "🟡"), ("LOW", "🟢")]:
            priority_tasks = [t for t in pending_tasks if t.priority == priority]

            if priority_tasks:
                content += (
                    f"## {emoji} {priority} Priority ({len(priority_tasks)} tasks)\n\n"
                )

                for task in priority_tasks:
                    content += f"- [ ] **⏳ {task.title}**"

                    if task.id.startswith("gen-") and task.status == "pending":
                        content += " 🆕"

                    content += "\n"

                    if task.description:
                        for line in task.description.split("\n"):
                            if line.strip():
                                content += f"  - {line.strip()}\n"

                    if task.estimated_effort:
                        content += f"  - ⏱️ **Effort:** {task.estimated_effort}\n"

                    if task.approach_suggestions:
                        content += f"  - 💡 **Suggestions:** {', '.join(task.approach_suggestions)}\n"

                    if task.related_files:
                        files = ", ".join(f"`{f}`" for f in task.related_files if f)
                        if files:
                            content += f"  - 📂 **Files:** {files}\n"

                    content += "\n"

        # Dodaj statystyki na dole
        content += "---\n"
        content += "*This file is automatically managed by goLLM* • "
        content += f"*{stats['completed']} of {stats['total']} tasks completed*"

        return content
