"""Remediation system for generating fixes for incorrect content"""

import json
from typing import List, Dict, Any, Optional, Literal
from datetime import datetime
from pydantic import BaseModel, Field

from .factoid import Factoid
from .llm import LLMClient
from .config import Config


class ContentUpdate(BaseModel):
    """Represents a suggested content update"""
    url: str = Field(description="URL of the content to update")
    location: str = Field(description="Location description (e.g., 'paragraph 3', 'line 42')")
    current_text: str = Field(description="Current (incorrect) text")
    suggested_text: str = Field(description="Suggested replacement text")
    reasoning: str = Field(description="Why this change is needed")
    confidence: float = Field(description="Confidence in the suggestion (0-1)")
    priority: str = Field(default="medium", description="low, medium, high, critical")
    factoid_id: Optional[str] = Field(default=None, description="Related factoid ID")


class OxenNote(BaseModel):
    """Represents a note in the Oxen truth registry"""
    factoid_id: str = Field(description="Related factoid ID")
    note_type: str = Field(description="correction_needed, verified, conflict, review")
    recommended_action: str = Field(description="What should be done")
    supporting_urls: List[str] = Field(default_factory=list, description="Supporting evidence")
    priority: str = Field(default="medium", description="low, medium, high, critical")
    created_at: datetime = Field(default_factory=datetime.now)


class GitHubIssue(BaseModel):
    """Represents a GitHub issue to be created"""
    title: str = Field(description="Issue title")
    body: str = Field(description="Issue body (markdown)")
    labels: List[str] = Field(default_factory=list, description="Issue labels")
    url: str = Field(description="URL being reported")
    factoid_ids: List[str] = Field(default_factory=list, description="Related factoid IDs")


class ContentUpdater:
    """Generate suggested content updates for incorrect claims"""
    
    def __init__(self, llm_client: LLMClient, config: Config):
        self.llm = llm_client
        self.config = config
    
    def generate_update(
        self,
        factoid: Factoid,
        surrounding_context: str,
        truth_evidence: str
    ) -> ContentUpdate:
        """
        Generate a suggested content update for a false factoid.
        
        Args:
            factoid: The factoid with low truth score
            surrounding_context: Context around the claim
            truth_evidence: Evidence of what is actually true
        
        Returns:
            ContentUpdate with suggested fix
        """
        prompt = f"""
Generate a content update to fix this incorrect technical claim.

INCORRECT CLAIM: {factoid.claim_text}
CONTEXT: {surrounding_context}
CORRECT INFORMATION: {truth_evidence}
SOURCE URL: {factoid.source_url}
CATEGORY: {factoid.category}

INSTRUCTIONS:
- Provide a clear, technically accurate replacement
- Match the tone and style of the original content
- Be specific and concise
- Explain why the change is needed

Respond with JSON:
{{
    "current_text": "the exact text to replace (with context)",
    "suggested_text": "the corrected version",
    "reasoning": "why this change is needed",
    "confidence": 0.0-1.0,
    "priority": "low|medium|high|critical"
}}
"""
        
        try:
            response = self.llm.client.chat.completions.create(
                model=self.config.model,
                messages=[
                    {
                        "role": "system",
                        "content": "You are a technical documentation editor. Generate precise, accurate content updates for technical documentation."
                    },
                    {
                        "role": "user",
                        "content": prompt
                    }
                ],
                temperature=0.2,
                max_tokens=1000,
                response_format={"type": "json_object"}
            )
            
            result = response.choices[0].message.content
            if result:
                data = json.loads(result)
                
                return ContentUpdate(
                    url=factoid.source_url,
                    location=f"Near: '{factoid.claim_text[:50]}...'",
                    current_text=data.get("current_text", factoid.claim_text),
                    suggested_text=data.get("suggested_text", ""),
                    reasoning=data.get("reasoning", ""),
                    confidence=data.get("confidence", 0.5),
                    priority=data.get("priority", "medium"),
                    factoid_id=factoid.factoid_id
                )
        
        except Exception as e:
            print(f"⚠️  Failed to generate update: {e}")
        
        # Fallback: basic update
        return ContentUpdate(
            url=factoid.source_url,
            location=f"Contains: '{factoid.claim_text}'",
            current_text=factoid.claim_text,
            suggested_text="[UPDATE NEEDED - LLM generation failed]",
            reasoning=f"Claim has low truth score ({factoid.truth_score:.2f})",
            confidence=0.3,
            priority="medium",
            factoid_id=factoid.factoid_id
        )
    
    def generate_batch_updates(
        self,
        factoids: List[Factoid],
        truth_evidence_map: Dict[str, str]
    ) -> List[ContentUpdate]:
        """Generate updates for multiple factoids"""
        updates = []
        
        for factoid in factoids:
            # Only generate updates for low-truth factoids
            if factoid.truth_score < 0.5:
                evidence = truth_evidence_map.get(factoid.factoid_id, "See official documentation")
                update = self.generate_update(
                    factoid,
                    factoid.surrounding_text,
                    evidence
                )
                updates.append(update)
        
        return updates


class OxenNoteCreator:
    """Create notes in Oxen registry for tracking issues"""
    
    def __init__(self, config: Config):
        self.config = config
        self.notes: List[OxenNote] = []
    
    def create_note(
        self,
        factoid: Factoid,
        note_type: str = "correction_needed",
        recommended_action: str = "",
        supporting_urls: Optional[List[str]] = None
    ) -> OxenNote:
        """
        Create a note for a factoid.
        
        Args:
            factoid: The factoid to annotate
            note_type: Type of note
            recommended_action: What should be done
            supporting_urls: Supporting evidence
        
        Returns:
            Created OxenNote
        """
        # Determine priority based on truth score
        if factoid.truth_score < 0.3:
            priority = "high"
        elif factoid.truth_score < 0.5:
            priority = "medium"
        else:
            priority = "low"
        
        note = OxenNote(
            factoid_id=factoid.factoid_id,
            note_type=note_type,
            recommended_action=recommended_action or f"Verify and update claim: {factoid.claim_text}",
            supporting_urls=supporting_urls or factoid.truth_sources,
            priority=priority
        )
        
        self.notes.append(note)
        return note
    
    def get_notes_by_priority(self, priority: str) -> List[OxenNote]:
        """Get all notes of a specific priority"""
        return [note for note in self.notes if note.priority == priority]
    
    def export_notes(self) -> List[Dict[str, Any]]:
        """Export notes as list of dicts for saving"""
        return [note.model_dump() for note in self.notes]


class GitHubIssueCreator:
    """Create GitHub issues for documentation problems"""
    
    def __init__(self, config: Config, llm_client: LLMClient):
        self.config = config
        self.llm = llm_client
    
    def create_issue(
        self,
        factoid: Factoid,
        repo_url: str,
        truth_evidence: str,
        pantsonfire_analysis_url: Optional[str] = None
    ) -> GitHubIssue:
        """
        Create a GitHub issue for an incorrect claim.
        
        Args:
            factoid: The factoid with the issue
            repo_url: GitHub repository URL
            truth_evidence: Evidence of what's actually true
            pantsonfire_analysis_url: Link to Oxen analysis
        
        Returns:
            GitHubIssue object
        """
        # Generate issue title
        title = f"Outdated documentation: {factoid.category.replace('_', ' ').title()}"
        
        # Generate issue body
        body = f"""## Documentation Issue Found by Pantsonfire

**Location**: {factoid.source_url}
**Category**: {factoid.category}
**Truth Score**: {factoid.truth_score:.2f} (Low confidence in accuracy)

### Issue Description
The documentation contains potentially outdated or incorrect information:

> {factoid.claim_text}

### Evidence
{truth_evidence}

### Suggested Action
Please review and update the documentation to reflect current information.

**Supporting Sources**:
{self._format_sources(factoid.truth_sources)}

**Conflicting Sources**:
{self._format_sources(factoid.conflict_sources)}

### Analysis Details
- **Extracted**: {factoid.extracted_at.isoformat()}
- **Content Type**: {factoid.content_type}
- **Confidence**: {factoid.confidence:.2f}
"""
        
        if pantsonfire_analysis_url:
            body += f"\n**Full Analysis**: {pantsonfire_analysis_url}\n"
        
        body += "\n---\n*This issue was automatically generated by [pantsonfire](https://github.com/realityinspector/pantsonfire), an open-source documentation fact-checker.*"
        
        # Determine labels
        labels = ["documentation", f"category:{factoid.category}"]
        
        if factoid.truth_score < 0.3:
            labels.append("priority:high")
        elif factoid.truth_score < 0.5:
            labels.append("priority:medium")
        
        return GitHubIssue(
            title=title,
            body=body,
            labels=labels,
            url=factoid.source_url,
            factoid_ids=[factoid.factoid_id]
        )
    
    def _format_sources(self, sources: List[str]) -> str:
        """Format source URLs as markdown list"""
        if not sources:
            return "*None*"
        
        return "\n".join(f"- {url}" for url in sources)
    
    def create_issue_on_github(
        self,
        issue: GitHubIssue,
        repo_owner: str,
        repo_name: str,
        github_token: str,
        dry_run: bool = True
    ) -> Optional[str]:
        """
        Actually create the issue on GitHub.
        
        Args:
            issue: The issue to create
            repo_owner: GitHub repo owner
            repo_name: GitHub repo name
            github_token: GitHub API token
            dry_run: If True, just print the issue without creating
        
        Returns:
            URL of created issue, or None if dry run or failed
        """
        if dry_run:
            print(f"\n{'='*80}")
            print(f"DRY RUN: Would create GitHub issue:")
            print(f"{'='*80}")
            print(f"Title: {issue.title}")
            print(f"Labels: {', '.join(issue.labels)}")
            print(f"\n{issue.body}")
            print(f"{'='*80}\n")
            return None
        
        try:
            import requests
            
            url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/issues"
            headers = {
                "Authorization": f"token {github_token}",
                "Accept": "application/vnd.github.v3+json"
            }
            
            data = {
                "title": issue.title,
                "body": issue.body,
                "labels": issue.labels
            }
            
            response = requests.post(url, headers=headers, json=data)
            
            if response.status_code == 201:
                issue_data = response.json()
                issue_url = issue_data.get("html_url")
                print(f"✅ Created GitHub issue: {issue_url}")
                return issue_url
            else:
                print(f"❌ Failed to create issue: {response.status_code} - {response.text}")
                return None
        
        except Exception as e:
            print(f"❌ Error creating GitHub issue: {e}")
            return None


class RemediationOrchestrator:
    """Orchestrate the entire remediation process"""
    
    def __init__(
        self,
        config: Config,
        llm_client: LLMClient,
        mode: Literal["suggestions", "oxen-notes", "github-issues"] = "suggestions"
    ):
        self.config = config
        self.llm = llm_client
        self.mode = mode
        
        self.content_updater = ContentUpdater(llm_client, config)
        self.note_creator = OxenNoteCreator(config)
        self.issue_creator = GitHubIssueCreator(config, llm_client)
    
    def remediate_factoids(
        self,
        factoids: List[Factoid],
        truth_evidence_map: Dict[str, str],
        dry_run: bool = True
    ) -> Dict[str, Any]:
        """
        Run remediation on low-truth factoids.
        
        Args:
            factoids: List of factoids to remediate
            truth_evidence_map: Map of factoid_id -> truth evidence
            dry_run: If True, don't actually create issues/PRs
        
        Returns:
            Remediation summary
        """
        # Filter to low-truth factoids
        low_truth = [f for f in factoids if f.truth_score < 0.5]
        
        results = {
            "total_factoids": len(factoids),
            "low_truth_count": len(low_truth),
            "mode": self.mode,
            "dry_run": dry_run,
            "updates": [],
            "notes": [],
            "issues": []
        }
        
        if self.mode == "suggestions":
            # Mode A: Generate content updates
            updates = self.content_updater.generate_batch_updates(low_truth, truth_evidence_map)
            results["updates"] = [u.model_dump() for u in updates]
            print(f"✅ Generated {len(updates)} content update suggestions")
        
        elif self.mode == "oxen-notes":
            # Mode B: Create Oxen notes
            for factoid in low_truth:
                note = self.note_creator.create_note(
                    factoid,
                    note_type="correction_needed",
                    recommended_action=f"Update: {factoid.claim_text}",
                    supporting_urls=factoid.truth_sources
                )
                results["notes"].append(note.model_dump())
            
            print(f"✅ Created {len(results['notes'])} Oxen notes")
        
        elif self.mode == "github-issues":
            # Mode C: Create GitHub issues
            for factoid in low_truth:
                # Determine repo from URL
                repo_info = self._extract_github_repo(factoid.source_url)
                
                if repo_info:
                    evidence = truth_evidence_map.get(factoid.factoid_id, "See official docs")
                    issue = self.issue_creator.create_issue(
                        factoid,
                        repo_info["repo_url"],
                        evidence
                    )
                    
                    # Create on GitHub if not dry run
                    if not dry_run and self.config.get("github_token"):
                        issue_url = self.issue_creator.create_issue_on_github(
                            issue,
                            repo_info["owner"],
                            repo_info["name"],
                            self.config.github_token,
                            dry_run=False
                        )
                        issue_dict = issue.model_dump()
                        issue_dict["created_url"] = issue_url
                        results["issues"].append(issue_dict)
                    else:
                        # Dry run
                        self.issue_creator.create_issue_on_github(
                            issue,
                            repo_info["owner"],
                            repo_info["name"],
                            "",
                            dry_run=True
                        )
                        results["issues"].append(issue.model_dump())
            
            print(f"✅ {'Would create' if dry_run else 'Created'} {len(results['issues'])} GitHub issues")
        
        return results
    
    def _extract_github_repo(self, url: str) -> Optional[Dict[str, str]]:
        """Extract GitHub repo information from a URL"""
        import re
        
        # Match GitHub URLs
        pattern = r'github\.com/([^/]+)/([^/]+)'
        match = re.search(pattern, url)
        
        if match:
            owner = match.group(1)
            repo = match.group(2).split('?')[0].split('#')[0]  # Clean query params
            
            return {
                "owner": owner,
                "name": repo,
                "repo_url": f"https://github.com/{owner}/{repo}"
            }
        
        return None
    
    def generate_summary_report(
        self,
        remediation_results: Dict[str, Any],
        output_path: Optional[str] = None
    ) -> str:
        """
        Generate a human-readable remediation report.
        
        Args:
            remediation_results: Results from remediate_factoids
            output_path: Optional path to save report
        
        Returns:
            Report text
        """
        report = []
        report.append("# Pantsonfire Remediation Report\n")
        report.append(f"**Generated**: {datetime.now().isoformat()}\n")
        report.append(f"**Mode**: {remediation_results['mode']}\n")
        report.append(f"**Dry Run**: {remediation_results['dry_run']}\n\n")
        
        report.append(f"## Summary\n")
        report.append(f"- Total Factoids Analyzed: {remediation_results['total_factoids']}\n")
        report.append(f"- Low-Truth Factoids: {remediation_results['low_truth_count']}\n\n")
        
        if remediation_results['mode'] == 'suggestions':
            report.append(f"## Content Update Suggestions ({len(remediation_results['updates'])})\n\n")
            for i, update in enumerate(remediation_results['updates'], 1):
                report.append(f"### Update #{i} [{update['priority'].upper()}]\n")
                report.append(f"**URL**: {update['url']}\n")
                report.append(f"**Current**: {update['current_text']}\n")
                report.append(f"**Suggested**: {update['suggested_text']}\n")
                report.append(f"**Reasoning**: {update['reasoning']}\n\n")
        
        elif remediation_results['mode'] == 'oxen-notes':
            report.append(f"## Oxen Notes ({len(remediation_results['notes'])})\n\n")
            for note in remediation_results['notes']:
                report.append(f"- [{note['priority'].upper()}] {note['recommended_action']}\n")
        
        elif remediation_results['mode'] == 'github-issues':
            report.append(f"## GitHub Issues ({len(remediation_results['issues'])})\n\n")
            for issue in remediation_results['issues']:
                report.append(f"### {issue['title']}\n")
                report.append(f"**URL**: {issue['url']}\n")
                report.append(f"**Labels**: {', '.join(issue['labels'])}\n")
                if issue.get('created_url'):
                    report.append(f"**Issue**: {issue['created_url']}\n")
                report.append("\n")
        
        report_text = "\n".join(report)
        
        # Save if path provided
        if output_path:
            with open(output_path, 'w') as f:
                f.write(report_text)
            print(f"📄 Report saved to: {output_path}")
        
        return report_text

