"""
LLMContext Project - Project management
"""

from datetime import datetime
from pathlib import Path
from typing import Any, Dict

import yaml

from .._compat import EMOJI
from ..domain.lifecycle import LifecycleManager
from ..utils.git import ensure_git_repo
from ..utils.llmstxt import LLMsTxtManager
from .generator import LLMContextGenerator
from .templates import TemplateManager


class Project:
    """Project management class"""

    def __init__(self, config: Dict[str, Any], output_dir: Path):
        self.config = config
        self.output_dir = output_dir
        # YAML source files go to .vibecollab/docs/ (isolated from project docs)
        self.docs_dir = output_dir / ".vibecollab" / "docs"

    @classmethod
    def create(
        cls, name: str, domain: str, output_dir: Path, role_based: bool = False
    ) -> "Project":
        """Create a new project

        Args:
            name: Project name
            domain: Business domain
            output_dir: Output directory
            role_based: Whether to enable multi-role mode
        """
        tm = TemplateManager()

        # Load base template
        config = tm.load_config("default")

        # Update project info
        config["project"]["name"] = name
        config["project"]["domain"] = domain

        # Enable multi-role mode
        if role_based:
            if "role_context" not in config:
                config["role_context"] = {}
            config["role_context"]["enabled"] = True

        # Merge domain extension
        try:
            ext_config = tm.load_config(domain)
            cls._merge_extension(config, ext_config)
        except FileNotFoundError:
            pass  # No domain extension, use default config

        # Initialize project lifecycle config
        lifecycle_manager = LifecycleManager.create_default(current_stage="demo")
        lifecycle_config = lifecycle_manager.to_config_dict()
        config.update(lifecycle_config)

        return cls(config, output_dir)

    @classmethod
    def load(cls, project_dir: Path) -> "Project":
        """Load existing project"""
        config_path = project_dir / "project.yaml"
        if not config_path.exists():
            raise FileNotFoundError(f"Project config not found: {config_path}")

        with open(config_path, "r", encoding="utf-8") as f:
            config = yaml.safe_load(f)

        return cls(config, project_dir)

    @staticmethod
    def _merge_extension(config: Dict, ext_config: Dict):
        """Merge domain extension config"""
        if not ext_config:
            return

        # Merge role overrides
        if "roles_override" in ext_config and ext_config["roles_override"]:
            for role in ext_config["roles_override"]:
                config["roles"] = [r for r in config.get("roles", []) if r["code"] != role["code"]]
                config["roles"].append(role)

        # Merge domain extensions
        domain_ext = ext_config.get("domain_extensions")
        if domain_ext:
            config.setdefault("domain_extensions", {})
            if config["domain_extensions"] is None:
                config["domain_extensions"] = {}
            config["domain_extensions"].update(domain_ext)

    def generate_all(self, auto_init_git: bool = False):
        """Generate all project files

        Args:
            auto_init_git: Whether to auto-initialize Git if not a repo
        """
        # Create directories
        self.output_dir.mkdir(parents=True, exist_ok=True)
        # YAML source files: .vibecollab/docs/
        self.docs_dir.mkdir(parents=True, exist_ok=True)
        # Markdown output: docs/
        (self.output_dir / "docs").mkdir(exist_ok=True)

        # Create .vibecollab/ directory (Insight / EventLog / vectors runtime data)
        vibecollab_dir = self.output_dir / ".vibecollab"
        vibecollab_dir.mkdir(exist_ok=True)
        (vibecollab_dir / "insights").mkdir(exist_ok=True)

        # .vibecollab/.gitignore -- exclude runtime data but keep directory structure
        vc_gitignore = vibecollab_dir / ".gitignore"
        if not vc_gitignore.exists():
            vc_gitignore.write_text(
                "# VibeCollab runtime data (auto-generated by vibecollab init)\n"
                "events.jsonl\n"
                "vectors/\n"
                "*.local.yaml\n",
                encoding="utf-8",
            )

        # Check and initialize Git repo
        self._ensure_git_repo(auto_init_git)

        # Save project config
        self._save_config()

        # Generate collaboration rules document
        self._generate_llm_txt()

        # Create document templates
        self._create_doc_templates()

    def _save_config(self):
        """Save project configuration"""
        config_path = self.output_dir / "project.yaml"
        with open(config_path, "w", encoding="utf-8") as f:
            yaml.dump(self.config, f, allow_unicode=True, sort_keys=False, default_flow_style=False)

    def _generate_llm_txt(self):
        """Generate collaboration rules document (CONTRIBUTING_AI.md) and integrate llms.txt"""
        generator = LLMContextGenerator(self.config, self.output_dir)
        content = generator.generate()

        # Output as CONTRIBUTING_AI.md
        contributing_ai_path = self.output_dir / "CONTRIBUTING_AI.md"
        contributing_ai_path.write_text(content, encoding="utf-8")

        # Integrate llms.txt
        project_name = self.config.get("project", {}).get("name", "Project")
        project_desc = self.config.get("project", {}).get(
            "description", "AI-assisted development project"
        )

        updated, llmstxt_path = LLMsTxtManager.ensure_integration(
            self.output_dir, project_name, project_desc, contributing_ai_path
        )

        # Save llms.txt path to config (for future updates)
        if llmstxt_path:
            self.config.setdefault("_meta", {})["llmstxt_path"] = str(llmstxt_path)

    def _create_doc_templates(self):
        """Create document templates (YAML-first, v0.12.0+)

        Core principle: YAML is source of truth → Markdown is a generated view.
        Creates YAML files in docs/ and renders Markdown views.
        """
        from jinja2 import Environment, FileSystemLoader

        project_name = self.config.get("project", {}).get("name", "Project")
        today = datetime.now().strftime("%Y-%m-%d")
        role_based_enabled = self.config.get("role_context", {}).get("enabled", False)

        # Setup Jinja2 for YAML template rendering
        package_dir = Path(__file__).parent.parent  # core/ -> vibecollab/
        templates_dir = package_dir / "templates" / "docs"
        jinja_env = Environment(loader=FileSystemLoader(str(templates_dir)))

        # Template context
        roles_config = self.config.get("roles", [])
        template_context = {
            "project_name": project_name,
            "today": today,
            "role_based": role_based_enabled,
            "roles": roles_config,
            "aggregated_from": [r["code"].lower() for r in roles_config] if roles_config else [],
        }

        # Multi-role mode: initialize role context
        if role_based_enabled:
            from ..domain.role import ContextAggregator, RoleManager

            dm = RoleManager(self.output_dir, self.config)
            current_dev = dm.get_current_role()

            # Initialize current role's context
            dm.init_role_context(current_dev)

            # Create COLLABORATION.md (still Markdown for human readability)
            collab_config = self.config.get("role_context", {}).get("collaboration", {})
            collab_file = self.output_dir / collab_config.get("file", ".vibecollab/roles/COLLABORATION.md")
            collab_file.parent.mkdir(parents=True, exist_ok=True)

            collab_content = f"""# {project_name} Role Collaboration Record

## Current Collaboration

(No collaboration records yet)

## Task Assignment Matrix

| Task | Owner | Collaborator | Status | Dependency |
|------|-------|--------------|--------|------------|
| Project init | {current_dev} | - | DONE | - |

## Handover Records

(No handover records yet)

---
*Last updated: {today}*
"""
            collab_file.write_text(collab_content, encoding="utf-8")

        # Generate YAML documents using templates
        yaml_files_created = []

        # 1. context.yaml (always created, single-role or multi-role source)
        context_template = jinja_env.get_template("context.yaml.j2")
        context_yaml = context_template.render(**template_context)
        context_yaml_path = self.docs_dir / "context.yaml"
        context_yaml_path.write_text(context_yaml, encoding="utf-8")
        yaml_files_created.append("context.yaml")

        # 2. decisions.yaml
        decisions_template = jinja_env.get_template("decisions.yaml.j2")
        decisions_yaml = decisions_template.render(**template_context)
        decisions_yaml_path = self.docs_dir / "decisions.yaml"
        decisions_yaml_path.write_text(decisions_yaml, encoding="utf-8")
        yaml_files_created.append("decisions.yaml")

        # 3. changelog.yaml
        changelog_template = jinja_env.get_template("changelog.yaml.j2")
        changelog_yaml = changelog_template.render(**template_context)
        changelog_yaml_path = self.docs_dir / "changelog.yaml"
        changelog_yaml_path.write_text(changelog_yaml, encoding="utf-8")
        yaml_files_created.append("changelog.yaml")

        # 4. roadmap.yaml
        roadmap_template = jinja_env.get_template("roadmap.yaml.j2")
        # Add lifecycle info to context
        lifecycle_manager = LifecycleManager(self.config)
        current_stage = lifecycle_manager.get_current_stage()
        stage_info = lifecycle_manager.get_stage_info()
        stage_history = lifecycle_manager.get_stage_history()
        current_stage_entry = stage_history[-1] if stage_history else None
        started_at = current_stage_entry.get("started_at", today) if current_stage_entry else today

        roadmap_context = {
            **template_context,
            "current_stage": current_stage,
            "stage_info": stage_info,
            "started_at": started_at,
        }
        roadmap_yaml = roadmap_template.render(**roadmap_context)
        roadmap_yaml_path = self.docs_dir / "roadmap.yaml"
        roadmap_yaml_path.write_text(roadmap_yaml, encoding="utf-8")
        yaml_files_created.append("roadmap.yaml")

        # 5. prd.yaml
        prd_template = jinja_env.get_template("prd.yaml.j2")
        prd_yaml = prd_template.render(**template_context)
        prd_yaml_path = self.docs_dir / "prd.yaml"
        prd_yaml_path.write_text(prd_yaml, encoding="utf-8")
        yaml_files_created.append("prd.yaml")

        # 6. qa.yaml
        qa_template = jinja_env.get_template("qa.yaml.j2")
        qa_yaml = qa_template.render(**template_context)
        qa_yaml_path = self.docs_dir / "qa.yaml"
        qa_yaml_path.write_text(qa_yaml, encoding="utf-8")
        yaml_files_created.append("qa.yaml")

        # Render Markdown views from YAML (YAML is source of truth)
        from .docs_renderer import DocsRenderer

        renderer = DocsRenderer()
        # Markdown output goes to docs/ directory (separate from YAML source)
        md_output_dir = self.output_dir / "docs"
        md_output_dir.mkdir(exist_ok=True)

        for kind, yaml_path in [
            ("context", context_yaml_path),
            ("decisions", decisions_yaml_path),
            ("changelog", changelog_yaml_path),
            ("roadmap", roadmap_yaml_path),
            ("prd", prd_yaml_path),
            ("qa", qa_yaml_path),
        ]:
            try:
                # Output Markdown to docs/, keeping YAML in .vibecollab/docs/
                output_filename = renderer.KIND_OUTPUT_FILES.get(kind, f"{kind.upper()}.md")
                output_path = md_output_dir / output_filename
                renderer.render_doc(yaml_path, output_path)
            except Exception:
                # If rendering fails, we still have the YAML
                pass

        # Multi-role mode: generate aggregated CONTEXT.md from role contexts
        if role_based_enabled:
            from ..domain.role import ContextAggregator

            aggregator = ContextAggregator(self.output_dir, self.config)
            aggregator.generate_and_save()

    def regenerate(self):
        """Regenerate collaboration rules document and update llms.txt"""
        # Check Git repo status (do not auto-init, only prompt)
        self._ensure_git_repo(auto_init=False)
        self._generate_llm_txt()

    def _ensure_git_repo(self, auto_init: bool = False):
        """Ensure the project is a Git repository

        Args:
            auto_init: Whether to auto-initialize if not present
        """
        success, message, is_new = ensure_git_repo(self.output_dir, auto_init=auto_init)

        if not success:
            # Save warning to config for CLI display
            self.config.setdefault("_meta", {})["git_warning"] = message
        elif is_new:
            # Record auto-initialization
            self.config.setdefault("_meta", {})["git_auto_init"] = True

    def _format_milestones(self, milestones: list) -> str:
        """Format milestone list

        Args:
            milestones: List of milestones

        Returns:
            str: Formatted milestone text
        """
        if not milestones:
            return "(No milestones)"

        lines = []
        for i, milestone in enumerate(milestones, 1):
            name = milestone.get("name", f"Milestone {i}")
            completed = milestone.get("completed", False)
            status = EMOJI["success"] if completed else EMOJI["hourglass"]
            lines.append(f"- {status} {name}")

        return "\n".join(lines)

    def _format_stage_history(self, history: list) -> str:
        """Format stage history

        Args:
            history: List of stage history entries

        Returns:
            str: Formatted history text
        """
        if not history:
            return "(No history)"

        lines = []
        for entry in history:
            stage = entry.get("stage", "unknown")
            started = entry.get("started_at", "Unknown")
            ended = entry.get("ended_at")

            if ended:
                lines.append(f"- **{stage}**: {started} -> {ended}")
            else:
                lines.append(f"- **{stage}**: {started} (In progress)")

        return "\n".join(lines)
