"""
LLMContext Project - Project management
"""

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

import yaml

from .._compat import EMOJI
from .generator import LLMContextGenerator
from ..utils.git import ensure_git_repo
from ..domain.lifecycle import LifecycleManager
from ..utils.llmstxt import LLMsTxtManager
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
        self.docs_dir = output_dir / "docs"

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

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

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

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

        # Enable multi-developer mode
        if multi_dev:
            if "multi_developer" not in config:
                config["multi_developer"] = {}
            config["multi_developer"]["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)
        self.docs_dir.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"""
        project_name = self.config.get("project", {}).get("name", "Project")
        today = datetime.now().strftime("%Y-%m-%d")
        multi_dev_enabled = self.config.get("multi_developer", {}).get("enabled", False)

        # Multi-developer mode: initialize developer context
        if multi_dev_enabled:
            from ..domain.developer import ContextAggregator, DeveloperManager

            dm = DeveloperManager(self.output_dir, self.config)
            current_dev = dm.get_current_developer()

            # Initialize current developer's context
            dm.init_developer_context(current_dev)

            # Create COLLABORATION.md
            collab_config = self.config.get('multi_developer', {}).get('collaboration', {})
            collab_file = self.output_dir / collab_config.get('file', 'docs/developers/COLLABORATION.md')
            collab_file.parent.mkdir(parents=True, exist_ok=True)

            collab_content = f"""# {project_name} Developer 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 global aggregated CONTEXT.md
            aggregator = ContextAggregator(self.output_dir, self.config)
            aggregator.generate_and_save()

        # DECISIONS.md
        decisions_content = f"""# {project_name} Decision Record

## Pending Decisions

(None)

## Confirmed Decisions

(None)

---
*Decision record format: see CONTRIBUTING_AI.md*
"""

        # CHANGELOG.md
        changelog_content = f"""# {project_name} Changelog

## [Unreleased]

### Added
- Project initialization
- Generated CONTRIBUTING_AI.md collaboration rules

---
"""

        # ROADMAP.md - includes project lifecycle stage info
        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_content = f"""# {project_name} Roadmap

## Current Project Lifecycle Stage

**Stage**: {stage_info.get('name', 'Unknown')} ({current_stage})
**Started**: {started_at}
**Description**: {stage_info.get('description', '')}

### Stage Focus
{chr(10).join(f"- {focus}" for focus in stage_info.get('focus', []))}

### Stage Principles
{chr(10).join(f"- {principle}" for principle in stage_info.get('principles', []))}

### Current Stage Milestones
{self._format_milestones(stage_info.get('milestones', []))}

---

## Milestones

### v0.1.0 - Project Initialization

- [ ] Determine project direction
- [ ] Set up development environment
- [ ] Complete core decisions

### Iteration Suggestion Pool

(None)

---

## Stage History

{self._format_stage_history(stage_history)}

---
"""

        # QA_TEST_CASES.md
        qa_content = f"""# {project_name} Test Case Manual

## Test Case Format

```
### TC-{{Module}}-{{Seq}}: {{Test Name}}
- **Related**: TASK-XXX
- **Precondition**: {{Precondition}}
- **Steps**:
  1. {{Step1}}
  2. {{Step2}}
- **Expected**: {{Expected Result}}
- **Status**: PASS/WARN/FAIL/SKIP
```

## Phase 0 Test Cases

(To be added)

---
"""

        # PRD.md - Product Requirements Document
        prd_content = f"""# {project_name} Product Requirements Document (PRD)

This document records the project's original requirements and requirement change history.

## Requirements List

(Requirements to be added)

---

## Requirements Statistics

| Status | Count |
|--------|-------|
| draft | 0 |
| confirmed | 0 |
| in_progress | 0 |
| completed | 0 |
| cancelled | 0 |

---

*Last updated: {today}*
"""

        # Write files
        if not multi_dev_enabled:
            # Single developer mode writes CONTEXT.md (multi-dev mode generates via aggregation)
            context_content = f"""# {project_name} Current Context

## Current Status
- **Phase**: Phase 0 - Project Initialization
- **Progress**: Just started
- **Next step**: Determine primary tasks

## Current Dialogue Goal
(To be filled)

## Pending Decisions
(To be filled)

## Completed Items
- [x] Project initialization
- [x] Generated CONTRIBUTING_AI.md

---
*Last updated: {today}*
"""
            (self.docs_dir / "CONTEXT.md").write_text(context_content, encoding="utf-8")

        (self.docs_dir / "DECISIONS.md").write_text(decisions_content, encoding="utf-8")
        (self.docs_dir / "CHANGELOG.md").write_text(changelog_content, encoding="utf-8")
        (self.docs_dir / "ROADMAP.md").write_text(roadmap_content, encoding="utf-8")
        (self.docs_dir / "QA_TEST_CASES.md").write_text(qa_content, encoding="utf-8")
        (self.docs_dir / "PRD.md").write_text(prd_content, encoding="utf-8")

    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)
