"""
GitHub Issues Synchronisation für das Issue Board
"""

import os
import sys
from pathlib import Path
from typing import Optional, List, Dict
from datetime import datetime

try:
    from github import Github, GithubException
    from github.Issue import Issue as GHIssue
    GITHUB_AVAILABLE = True
except ImportError:
    GITHUB_AVAILABLE = False

from .issue_board import IssueBoard, Issue, IssueStatus, IssuePriority


class GitHubSync:
    """Synchronisiert lokale Issues mit GitHub Issues"""
    
    # Mapping zwischen lokalem Status und GitHub-Labels
    STATUS_LABELS = {
        "todo": "status: todo",
        "in_progress": "status: in progress",
        "done": "status: done",
        "blocked": "status: blocked"
    }
    
    PRIORITY_LABELS = {
        "low": "priority: low",
        "medium": "priority: medium",
        "high": "priority: high",
        "critical": "priority: critical"
    }
    
    def __init__(self, token: Optional[str] = None, repo: Optional[str] = None):
        """
        Initialisiert GitHub-Synchronisation
        
        Args:
            token: GitHub Personal Access Token (optional, wird aus verschiedenen Quellen geladen)
            repo: Repository im Format "owner/repo" (optional, wird automatisch erkannt)
        """
        if not GITHUB_AVAILABLE:
            raise ImportError(
                "PyGithub ist nicht installiert. Installieren Sie es mit: "
                "pip install PyGithub"
            )
        
        self.token = token or self._get_token()
        if not self.token:
            raise ValueError(
                "GitHub Token nicht gefunden. Bitte setzen Sie:\n"
                "1. Umgebungsvariable: export GITHUB_TOKEN=your_token\n"
                "2. Config-Datei: ~/.vogel_config.json\n"
                "3. CLI-Parameter: --github-token your_token"
            )
        
        self.github = Github(self.token)
        self.repo_name = repo or self._detect_repo()
        
        try:
            self.repo = self.github.get_repo(self.repo_name)
        except GithubException as e:
            raise ValueError(f"Repository '{self.repo_name}' nicht gefunden: {e}")
    
    def _get_token(self) -> Optional[str]:
        """
        Lädt GitHub Token aus verschiedenen Quellen
        
        Priorität:
        1. Umgebungsvariable GITHUB_TOKEN
        2. Umgebungsvariable GH_TOKEN
        3. Config-Datei ~/.vogel_config.json
        4. Git credential helper
        """
        # 1. Umgebungsvariablen
        token = os.environ.get('GITHUB_TOKEN') or os.environ.get('GH_TOKEN')
        if token:
            return token
        
        # 2. Config-Datei
        config_path = Path.home() / '.vogel_config.json'
        if config_path.exists():
            try:
                import json
                with open(config_path, 'r') as f:
                    config = json.load(f)
                    token = config.get('github_token')
                    if token:
                        return token
            except Exception:
                pass
        
        return None
    
    def _detect_repo(self) -> str:
        """
        Erkennt Repository aus Git-Konfiguration
        
        Returns:
            Repository im Format "owner/repo"
        """
        try:
            import subprocess
            result = subprocess.run(
                ['git', 'config', '--get', 'remote.origin.url'],
                capture_output=True,
                text=True,
                check=True
            )
            
            url = result.stdout.strip()
            
            # Parse GitHub URL
            # Formate: git@github.com:owner/repo.git oder https://github.com/owner/repo.git
            if 'github.com' in url:
                if url.startswith('git@'):
                    # git@github.com:owner/repo.git
                    parts = url.split(':')[1].replace('.git', '')
                else:
                    # https://github.com/owner/repo.git
                    parts = url.split('github.com/')[1].replace('.git', '')
                return parts
        except Exception:
            pass
        
        # Fallback auf vogel-video-analyzer Repository
        return "kamera-linux/vogel-video-analyzer"
    
    def _issue_to_github_format(self, issue: Issue) -> Dict:
        """Konvertiert lokales Issue zu GitHub-Format"""
        labels = []
        
        # Status-Label hinzufügen
        if issue.status in self.STATUS_LABELS:
            labels.append(self.STATUS_LABELS[issue.status])
        
        # Prioritäts-Label hinzufügen
        if issue.priority in self.PRIORITY_LABELS:
            labels.append(self.PRIORITY_LABELS[issue.priority])
        
        # Benutzerdefinierte Labels hinzufügen
        labels.extend(issue.labels)
        
        return {
            'title': issue.title,
            'body': self._format_issue_body(issue),
            'labels': labels,
            'assignee': issue.assignee
        }
    
    def _format_issue_body(self, issue: Issue) -> str:
        """Formatiert Issue-Body für GitHub"""
        body = issue.description + "\n\n---\n\n"
        body += f"**Local Issue ID:** #{issue.id}\n"
        body += f"**Created:** {issue.created_at}\n"
        body += f"**Updated:** {issue.updated_at}\n"
        return body
    
    def _github_to_local_issue(self, gh_issue: GHIssue, local_id: Optional[int] = None) -> Dict:
        """Konvertiert GitHub Issue zu lokalem Format"""
        # Status aus Labels extrahieren
        status = "todo"
        priority = "medium"
        custom_labels = []
        
        for label in gh_issue.labels:
            label_name = label.name
            
            # Status-Label
            for local_status, gh_label in self.STATUS_LABELS.items():
                if label_name == gh_label:
                    status = local_status
                    break
            
            # Prioritäts-Label
            for local_priority, gh_label in self.PRIORITY_LABELS.items():
                if label_name == gh_label:
                    priority = local_priority
                    break
            
            # Andere Labels
            if (label_name not in self.STATUS_LABELS.values() and 
                label_name not in self.PRIORITY_LABELS.values()):
                custom_labels.append(label_name)
        
        return {
            'id': local_id or gh_issue.number,
            'title': gh_issue.title,
            'description': gh_issue.body or "",
            'status': status,
            'priority': priority,
            'labels': custom_labels,
            'assignee': gh_issue.assignee.login if gh_issue.assignee else None,
            'created_at': gh_issue.created_at.isoformat(),
            'updated_at': gh_issue.updated_at.isoformat()
        }
    
    def push_issue(self, issue: Issue, update_existing: bool = True) -> GHIssue:
        """
        Pusht ein lokales Issue zu GitHub
        
        Args:
            issue: Lokales Issue
            update_existing: Aktualisiere existierende Issues
        
        Returns:
            GitHub Issue Objekt
        """
        gh_data = self._issue_to_github_format(issue)
        
        # Suche nach existierendem Issue (anhand Titel oder ID im Body)
        existing = None
        if update_existing:
            for gh_issue in self.repo.get_issues(state='all'):
                if f"Local Issue ID:** #{issue.id}" in (gh_issue.body or ""):
                    existing = gh_issue
                    break
        
        if existing:
            # Aktualisiere existierendes Issue
            existing.edit(
                title=gh_data['title'],
                body=gh_data['body'],
                labels=gh_data['labels']
            )
            if gh_data['assignee']:
                existing.add_to_assignees(gh_data['assignee'])
            
            # Schließe Issue wenn Status "done"
            if issue.status == "done" and existing.state == "open":
                existing.edit(state='closed')
            elif issue.status != "done" and existing.state == "closed":
                existing.edit(state='open')
            
            return existing
        else:
            # Erstelle neues Issue
            gh_issue = self.repo.create_issue(
                title=gh_data['title'],
                body=gh_data['body'],
                labels=gh_data['labels'],
                assignee=gh_data['assignee']
            )
            return gh_issue
    
    def pull_issues(self, board: IssueBoard, state: str = 'open') -> List[Issue]:
        """
        Holt GitHub Issues und erstellt/aktualisiert lokale Issues
        
        Args:
            board: Lokales Issue Board
            state: GitHub Issue State ('open', 'closed', 'all')
        
        Returns:
            Liste der synchronisierten Issues
        """
        synced_issues = []
        
        for gh_issue in self.repo.get_issues(state=state):
            # Prüfe ob Issue bereits lokal existiert
            local_id = None
            for local_issue in board.issues:
                # Suche anhand GitHub Issue Number im Body
                if str(gh_issue.number) in str(local_issue.id):
                    local_id = local_issue.id
                    break
            
            issue_data = self._github_to_local_issue(gh_issue, local_id)
            
            if local_id:
                # Aktualisiere existierendes lokales Issue
                board.update_issue(
                    local_id,
                    title=issue_data['title'],
                    description=issue_data['description'],
                    status=issue_data['status'],
                    priority=issue_data['priority'],
                    labels=issue_data['labels'],
                    assignee=issue_data['assignee']
                )
                issue = board.get_issue(local_id)
            else:
                # Erstelle neues lokales Issue
                issue = board.create_issue(
                    title=issue_data['title'],
                    description=issue_data['description'],
                    status=issue_data['status'],
                    priority=issue_data['priority'],
                    labels=issue_data['labels'],
                    assignee=issue_data['assignee']
                )
            
            synced_issues.append(issue)
        
        return synced_issues
    
    def sync_all(self, board: IssueBoard, direction: str = 'both') -> Dict:
        """
        Synchronisiert alle Issues
        
        Args:
            board: Lokales Issue Board
            direction: 'push' (lokal -> GitHub), 'pull' (GitHub -> lokal), 'both'
        
        Returns:
            Statistiken über die Synchronisation
        """
        stats = {
            'pushed': 0,
            'pulled': 0,
            'errors': []
        }
        
        if direction in ['push', 'both']:
            for issue in board.issues:
                try:
                    self.push_issue(issue)
                    stats['pushed'] += 1
                except Exception as e:
                    stats['errors'].append(f"Push Issue #{issue.id}: {str(e)}")
        
        if direction in ['pull', 'both']:
            try:
                synced = self.pull_issues(board, state='all')
                stats['pulled'] = len(synced)
            except Exception as e:
                stats['errors'].append(f"Pull: {str(e)}")
        
        return stats
    
    @staticmethod
    def setup_token_interactive():
        """Interaktive Token-Einrichtung"""
        print("=" * 60)
        print("GitHub Token Einrichtung")
        print("=" * 60)
        print("\nUm GitHub Issues zu synchronisieren, benötigen Sie einen")
        print("Personal Access Token von GitHub.")
        print("\nSchritte:")
        print("1. Gehen Sie zu: https://github.com/settings/tokens")
        print("2. Klicken Sie auf 'Generate new token (classic)'")
        print("3. Wählen Sie 'repo' scope (voller Repository-Zugriff)")
        print("4. Kopieren Sie den generierten Token")
        print("\nSpeichermethoden:")
        print("A) Umgebungsvariable (empfohlen):")
        print("   export GITHUB_TOKEN=your_token_here")
        print("   (Fügen Sie dies zu ~/.bashrc oder ~/.zshrc hinzu)")
        print("\nB) Config-Datei:")
        print("   Speichern in ~/.vogel_config.json")
        print("\nC) CLI-Parameter:")
        print("   vogel-issues sync --github-token your_token_here")
        print("\n" + "=" * 60)
        
        choice = input("\nToken jetzt in Config-Datei speichern? [y/N]: ")
        
        if choice.lower() == 'y':
            token = input("GitHub Token eingeben: ").strip()
            if token:
                import json
                config_path = Path.home() / '.vogel_config.json'
                config = {}
                
                if config_path.exists():
                    with open(config_path, 'r') as f:
                        config = json.load(f)
                
                config['github_token'] = token
                
                with open(config_path, 'w') as f:
                    json.dump(config, f, indent=2)
                
                # Setze sichere Berechtigungen
                config_path.chmod(0o600)
                
                print(f"\n✅ Token gespeichert in {config_path}")
                print("⚠️  WICHTIG: Teilen Sie diese Datei niemals!")
                return True
        
        return False
