"""
Enhanced Jira Operations Module
Comprehensive read, write, and append operations for Jira content
"""

import logging
import re
from typing import Dict, List, Any, Optional
from .jira_connector import JiraConnector


class JiraOperations:
    """
    Enhanced operations for Jira content management.
    Provides comprehensive read, write, append, and advanced functionalities.
    """

    def __init__(self, connector: JiraConnector):
        """
        Initialize operations with a connector instance

        Args:
            connector: JiraConnector instance
        """
        self.connector = connector
        self.logger = logging.getLogger(__name__)

    # ==================== READ OPERATIONS ====================

    def read_issue(self, issue_key: str, fields: Optional[List[str]] = None) -> Dict[str, Any]:
        """Read issue details and metadata"""
        try:
            # Get issue data
            issue = self.connector.get_issue(issue_key, fields)

            # Extract metadata
            metadata = {
                "key": issue.get("key"),
                "id": issue.get("id"),
                "self": issue.get("self"),
                "fields": issue.get("fields", {}),
                "changelog": issue.get("changelog", {}),
                "transitions": None,
                "project": issue.get("fields", {}).get("project", {}),
                "issuetype": issue.get("fields", {}).get("issuetype", {}),
                "status": issue.get("fields", {}).get("status", {}),
                "priority": issue.get("fields", {}).get("priority", {}),
                "assignee": issue.get("fields", {}).get("assignee", {}),
                "reporter": issue.get("fields", {}).get("reporter", {}),
                "created": issue.get("fields", {}).get("created"),
                "updated": issue.get("fields", {}).get("updated"),
                "resolution": issue.get("fields", {}).get("resolution"),
                "resolutiondate": issue.get("fields", {}).get("resolutiondate")
            }

            # Get available transitions
            try:
                transitions = self.connector.get_issue_transitions(issue_key)
                metadata["transitions"] = transitions
            except Exception:
                pass

            return {
                "data": issue,
                "metadata": metadata,
                "success": True
            }

        except Exception as e:
            self.logger.error(f"Failed to read issue {issue_key}: {e}")
            return {
                "data": {},
                "metadata": {},
                "success": False,
                "error": str(e)
            }

    def read_project_issues(
        self,
        project_key: str,
        fields: Optional[List[str]] = None,
        limit: int = 50,
        start_at: int = 0
    ) -> List[Dict[str, Any]]:
        """Read all issues from a specific project"""
        try:
            result = self.connector.get_project_issues(project_key, fields, limit, start_at)
            issues = result.get("issues", [])
            
            processed_issues = []
            for issue in issues:
                issue_data = self.read_issue(issue.get("key"), fields)
                if issue_data["success"]:
                    processed_issues.append(issue_data)

            return processed_issues

        except Exception as e:
            self.logger.error(f"Failed to read project issues for {project_key}: {e}")
            return []

    def read_projects(self) -> List[Dict[str, Any]]:
        """Read all accessible projects"""
        try:
            projects = self.connector.get_projects()
            return projects

        except Exception as e:
            self.logger.error(f"Failed to read projects: {e}")
            return []

    def read_search_results(
        self,
        jql: str,
        fields: Optional[List[str]] = None,
        limit: int = 50
    ) -> List[Dict[str, Any]]:
        """Read search results for JQL query"""
        try:
            result = self.connector.search_issues(jql, fields, limit)
            issues = result.get("issues", [])
            
            processed_issues = []
            for issue in issues:
                issue_data = self.read_issue(issue.get("key"), fields)
                if issue_data["success"]:
                    processed_issues.append(issue_data)

            return processed_issues

        except Exception as e:
            self.logger.error(f"Failed to read search results for JQL '{jql}': {e}")
            return []

    def read_fields(self) -> List[Dict[str, Any]]:
        """Read all available fields"""
        try:
            return self.connector.get_available_fields()

        except Exception as e:
            self.logger.error(f"Failed to read fields: {e}")
            return []

    def read_custom_fields(self) -> List[Dict[str, Any]]:
        """Read all custom fields"""
        try:
            return self.connector.get_custom_fields()

        except Exception as e:
            self.logger.error(f"Failed to read custom fields: {e}")
            return []

    def read_comments(self, issue_key: str) -> List[Dict[str, Any]]:
        """Read all comments for an issue"""
        try:
            # Get issue with comments field
            issue = self.connector.get_issue(issue_key, ["comment"])
            comments = issue.get("fields", {}).get("comment", {}).get("comments", [])
            
            processed_comments = []
            for comment in comments:
                comment_data = {
                    "id": comment.get("id"),
                    "author": comment.get("author", {}).get("displayName"),
                    "author_avatar": comment.get("author", {}).get("avatarUrls", {}).get("48x48"),
                    "body": comment.get("body"),
                    "created": comment.get("created"),
                    "updated": comment.get("updated"),
                    "self": comment.get("self"),
                    "visibility": comment.get("visibility"),
                    "replies": []
                }
                processed_comments.append(comment_data)

            return processed_comments

        except Exception as e:
            self.logger.error(f"Failed to read comments for issue {issue_key}: {e}")
            return []

    def read_issue_worklogs(self, issue_key: str) -> List[Dict[str, Any]]:
        """Read worklogs for an issue"""
        try:
            # This would require additional API endpoints not in current connector
            # For now, return a placeholder
            return []
        except Exception as e:
            self.logger.error(f"Failed to read worklogs for issue {issue_key}: {e}")
            return []

    def read_issue_links(self, issue_key: str) -> List[Dict[str, Any]]:
        """Read issue links for an issue"""
        try:
            # This would require additional API endpoints not in current connector
            # For now, return a placeholder
            return []
        except Exception as e:
            self.logger.error(f"Failed to read issue links for {issue_key}: {e}")
            return []

    def read_project_components(self, project_key: str) -> List[Dict[str, Any]]:
        """Read project components"""
        try:
            # This would require additional API endpoints not in current connector
            # For now, return a placeholder
            return []
        except Exception as e:
            self.logger.error(f"Failed to read components for project {project_key}: {e}")
            return []

    def read_project_versions(self, project_key: str) -> List[Dict[str, Any]]:
        """Read project versions"""
        try:
            # This would require additional API endpoints not in current connector
            # For now, return a placeholder
            return []
        except Exception as e:
            self.logger.error(f"Failed to read versions for project {project_key}: {e}")
            return []

    def read_sprints(self, board_id: int) -> List[Dict[str, Any]]:
        """Read sprints for a board"""
        try:
            # This would require additional API endpoints not in current connector
            # For now, return a placeholder
            return []
        except Exception as e:
            self.logger.error(f"Failed to read sprints for board {board_id}: {e}")
            return []

    def read_boards(self, project_key: Optional[str] = None) -> List[Dict[str, Any]]:
        """Read boards"""
        try:
            # This would require additional API endpoints not in current connector
            # For now, return a placeholder
            return []
        except Exception as e:
            self.logger.error(f"Failed to read boards: {e}")
            return []

    # ==================== WRITE OPERATIONS ====================

    def write_issue(
        self,
        project_key: str,
        issue_type: str,
        summary: str,
        description: Optional[str] = None,
        **fields
    ) -> Dict[str, Any]:
        """Write/create a new issue"""
        try:
            issue = self.connector.create_issue(
                project_key=project_key,
                issue_type=issue_type,
                summary=summary,
                description=description,
                **fields
            )

            return {
                "issue_key": issue.get("key"),
                "issue_id": issue.get("id"),
                "self": issue.get("self"),
                "url": f"{self.connector.jira_url}/browse/{issue.get('key')}",
                "success": True
            }

        except Exception as e:
            self.logger.error(f"Failed to write issue '{summary}': {e}")
            return {
                "issue_key": None,
                "success": False,
                "error": str(e)
            }

    def write_comment(self, issue_key: str, comment: str) -> Dict[str, Any]:
        """Write/add a comment to an issue"""
        try:
            comment_data = self.connector.add_comment(issue_key, comment)

            return {
                "comment_id": comment_data.get("id"),
                "self": comment_data.get("self"),
                "url": f"{self.connector.jira_url}/browse/{issue_key}?focusedCommentId={comment_data.get('id')}",
                "success": True
            }

        except Exception as e:
            self.logger.error(f"Failed to write comment to issue {issue_key}: {e}")
            return {
                "comment_id": None,
                "success": False,
                "error": str(e)
            }

    def write_issue_update(self, issue_key: str, **fields) -> Dict[str, Any]:
        """Write/update an existing issue"""
        try:
            updated_issue = self.connector.update_issue(issue_key, **fields)

            return {
                "issue_key": issue_key,
                "updated_fields": list(fields.keys()),
                "new_version": updated_issue.get("fields", {}).get("updated", {}).get("name"),
                "url": f"{self.connector.jira_url}/browse/{issue_key}",
                "success": True
            }

        except Exception as e:
            self.logger.error(f"Failed to update issue {issue_key}: {e}")
            return {
                "issue_key": issue_key,
                "success": False,
                "error": str(e)
            }

    def write_worklog(self, issue_key: str, time_spent: str, comment: Optional[str] = None) -> Dict[str, Any]:
        """Write worklog to an issue"""
        try:
            # This would require additional API endpoints not in current connector
            return {
                "issue_key": issue_key,
                "success": False,
                "error": "Worklog creation not implemented in current connector version"
            }
        except Exception as e:
            return {"success": False, "error": str(e)}

    def write_issue_link(self, inward_issue: str, outward_issue: str, link_type: str) -> Dict[str, Any]:
        """Create link between issues"""
        try:
            # This would require additional API endpoints not in current connector
            return {
                "inward_issue": inward_issue,
                "outward_issue": outward_issue,
                "success": False,
                "error": "Issue linking not implemented in current connector version"
            }
        except Exception as e:
            return {"success": False, "error": str(e)}

    def write_component(self, project_key: str, name: str, description: str = "") -> Dict[str, Any]:
        """Create project component"""
        try:
            # This would require additional API endpoints not in current connector
            return {
                "project_key": project_key,
                "name": name,
                "success": False,
                "error": "Component creation not implemented in current connector version"
            }
        except Exception as e:
            return {"success": False, "error": str(e)}

    def write_version(self, project_key: str, name: str, description: str = "") -> Dict[str, Any]:
        """Create project version"""
        try:
            # This would require additional API endpoints not in current connector
            return {
                "project_key": project_key,
                "name": name,
                "success": False,
                "error": "Version creation not implemented in current connector version"
            }
        except Exception as e:
            return {"success": False, "error": str(e)}

    # ==================== APPEND OPERATIONS ====================

    def append_comment_to_issue(self, issue_key: str, comment: str) -> Dict[str, Any]:
        """Append a comment to an issue (alias for write_comment)"""
        return self.write_comment(issue_key, comment)

    def append_to_description(self, issue_key: str, content_to_append: str) -> Dict[str, Any]:
        """Append content to issue description"""
        try:
            # Read current issue
            current_data = self.read_issue(issue_key, ["description"])
            if not current_data["success"]:
                return current_data

            # Get current description
            current_desc = current_data["data"].get("fields", {}).get("description", "")
            
            # Append new content
            updated_description = current_desc + "\n\n" + content_to_append

            # Update the issue
            result = self.write_issue_update(issue_key, description=updated_description)
            
            if result["success"]:
                result["appended_content"] = content_to_append
                result["original_length"] = len(current_desc) if current_desc else 0
                result["final_length"] = len(updated_description)

            return result

        except Exception as e:
            self.logger.error(f"Failed to append to description for issue {issue_key}: {e}")
            return {
                "issue_key": issue_key,
                "success": False,
                "error": str(e)
            }

    # ==================== TRANSITION OPERATIONS ====================

    def read_transitions(self, issue_key: str) -> List[Dict[str, Any]]:
        """Read available transitions for an issue"""
        try:
            return self.connector.get_issue_transitions(issue_key)

        except Exception as e:
            self.logger.error(f"Failed to read transitions for issue {issue_key}: {e}")
            return []

    def write_transition(self, issue_key: str, transition_id: str, comment: Optional[str] = None) -> Dict[str, Any]:
        """Write/execute a transition for an issue"""
        try:
            success = self.connector.transition_issue(issue_key, transition_id)

            return {
                "issue_key": issue_key,
                "transition_id": transition_id,
                "comment": comment,
                "url": f"{self.connector.jira_url}/browse/{issue_key}",
                "success": success
            }

        except Exception as e:
            self.logger.error(f"Failed to execute transition for issue {issue_key}: {e}")
            return {
                "issue_key": issue_key,
                "transition_id": transition_id,
                "success": False,
                "error": str(e)
            }

    # ==================== SEARCH OPERATIONS ====================

    def search_issues(
        self,
        jql: str,
        fields: Optional[List[str]] = None,
        limit: int = 50
    ) -> List[Dict[str, Any]]:
        """Search for issues using JQL"""
        return self.read_search_results(jql, fields, limit)

    def search_issues_by_text(self, text: str, project_key: Optional[str] = None, limit: int = 50) -> List[Dict[str, Any]]:
        """Search issues containing specific text"""
        jql = f'text ~ "{text}"'
        if project_key:
            jql += f' AND project = "{project_key}"'
        return self.search_issues(jql, limit=limit)

    def search_issues_by_status(self, status: str, project_key: Optional[str] = None, limit: int = 50) -> List[Dict[str, Any]]:
        """Search issues by status"""
        jql = f'status = "{status}"'
        if project_key:
            jql += f' AND project = "{project_key}"'
        return self.search_issues(jql, limit=limit)

    def search_issues_by_assignee(self, assignee: str, project_key: Optional[str] = None, limit: int = 50) -> List[Dict[str, Any]]:
        """Search issues by assignee"""
        jql = f'assignee = "{assignee}"'
        if project_key:
            jql += f' AND project = "{project_key}"'
        return self.search_issues(jql, limit=limit)

    def search_issues_by_priority(self, priority: str, project_key: Optional[str] = None, limit: int = 50) -> List[Dict[str, Any]]:
        """Search issues by priority"""
        jql = f'priority = "{priority}"'
        if project_key:
            jql += f' AND project = "{project_key}"'
        return self.search_issues(jql, limit=limit)

    def search_issues_by_type(self, issue_type: str, project_key: Optional[str] = None, limit: int = 50) -> List[Dict[str, Any]]:
        """Search issues by type"""
        jql = f'issuetype = "{issue_type}"'
        if project_key:
            jql += f' AND project = "{project_key}"'
        return self.search_issues(jql, limit=limit)

    # ==================== BATCH OPERATIONS ====================

    def batch_read_issues(self, issue_keys: List[str], fields: Optional[List[str]] = None) -> List[Dict[str, Any]]:
        """Read multiple issues in batch"""
        results = []
        for issue_key in issue_keys:
            issue_data = self.read_issue(issue_key, fields)
            results.append(issue_data)
        return results

    def batch_write_issues(self, issues_data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """Write multiple issues in batch"""
        results = []
        for issue_data in issues_data:
            result = self.write_issue(
                project_key=issue_data.get("project_key"),
                issue_type=issue_data.get("issue_type"),
                summary=issue_data.get("summary"),
                description=issue_data.get("description"),
                **issue_data.get("additional_fields", {})
            )
            results.append(result)
        return results

    def batch_write_comments(self, comments_data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """Write multiple comments in batch"""
        results = []
        for comment_data in comments_data:
            result = self.write_comment(
                issue_key=comment_data.get("issue_key"),
                comment=comment_data.get("comment")
            )
            results.append(result)
        return results

    def batch_update_issues(self, updates_data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """Update multiple issues in batch"""
        results = []
        for update_data in updates_data:
            result = self.write_issue_update(
                issue_key=update_data.get("issue_key"),
                **update_data.get("fields", {})
            )
            results.append(result)
        return results

    def batch_transition_issues(self, transitions_data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """Transition multiple issues in batch"""
        results = []
        for transition_data in transitions_data:
            result = self.write_transition(
                issue_key=transition_data.get("issue_key"),
                transition_id=transition_data.get("transition_id"),
                comment=transition_data.get("comment")
            )
            results.append(result)
        return results

    # ==================== UTILITY OPERATIONS ====================

    def format_issue_for_display(self, issue: Dict[str, Any], fields: Optional[List[str]] = None) -> str:
        """Format issue for human-readable display"""
        try:
            return self.connector.format_issue_for_display(issue, fields)

        except Exception as e:
            self.logger.error(f"Failed to format issue for display: {e}")
            return f"Error formatting issue: {e}"

    def test_connection(self) -> bool:
        """Test connection to Jira"""
        try:
            return self.connector.test_connection()

        except Exception as e:
            self.logger.error(f"Connection test failed: {e}")
            return False

    def get_issue_statistics(self, issue_key: str) -> Dict[str, Any]:
        """Get comprehensive issue statistics"""
        try:
            issue_data = self.read_issue(issue_key)
            if not issue_data["success"]:
                return issue_data

            comments = self.read_comments(issue_key)
            transitions = self.read_transitions(issue_key)

            metadata = issue_data["metadata"]
            description = metadata.get("fields", {}).get("description", "")

            stats = {
                "issue_key": issue_key,
                "summary": metadata.get("fields", {}).get("summary", ""),
                "status": metadata.get("status", {}).get("name", ""),
                "priority": metadata.get("priority", {}).get("name", ""),
                "assignee": metadata.get("assignee", {}).get("displayName", "Unassigned"),
                "reporter": metadata.get("reporter", {}).get("displayName", ""),
                "issue_type": metadata.get("issuetype", {}).get("name", ""),
                "project": metadata.get("project", {}).get("name", ""),
                "description_length": len(description) if description else 0,
                "word_count": len(description.split()) if description else 0,
                "comment_count": len(comments),
                "available_transitions": len(transitions),
                "created_date": metadata.get("created"),
                "updated_date": metadata.get("updated"),
                "resolution_date": metadata.get("resolutiondate"),
                "is_resolved": bool(metadata.get("resolution")),
                "has_comments": len(comments) > 0,
                "has_transitions": len(transitions) > 0
            }

            return {"statistics": stats, "success": True}

        except Exception as e:
            return {"statistics": {}, "success": False, "error": str(e)}

    def export_issue_data(self, issue_key: str, format_type: str = "json") -> Dict[str, Any]:
        """Export issue data in various formats"""
        try:
            issue_data = self.read_issue(issue_key)
            if not issue_data["success"]:
                return issue_data

            if format_type == "json":
                return {
                    "data": issue_data,
                    "format": format_type,
                    "issue_key": issue_key,
                    "success": True
                }
            elif format_type == "summary":
                metadata = issue_data["metadata"]
                summary = f"""
Issue: {metadata.get('key')} - {metadata.get('fields', {}).get('summary', '')}
Project: {metadata.get('project', {}).get('name', '')}
Status: {metadata.get('status', {}).get('name', '')}
Priority: {metadata.get('priority', {}).get('name', '')}
Assignee: {metadata.get('assignee', {}).get('displayName', 'Unassigned')}
Reporter: {metadata.get('reporter', {}).get('displayName', '')}
Type: {metadata.get('issuetype', {}).get('name', '')}
Created: {metadata.get('created', '')}
Updated: {metadata.get('updated', '')}

Description:
{metadata.get('fields', {}).get('description', '')[:500]}...
                """.strip()
                return {
                    "data": summary,
                    "format": format_type,
                    "issue_key": issue_key,
                    "success": True
                }
            else:
                return {
                    "data": issue_data,
                    "format": "json",
                    "issue_key": issue_key,
                    "success": True
                }

        except Exception as e:
            return {
                "data": "",
                "format": format_type,
                "issue_key": issue_key,
                "success": False,
                "error": str(e)
            }

    def close(self):
        """Close the connection"""
        if hasattr(self.connector, 'close'):
            self.connector.close()
            self.logger.info("Jira operations session closed")
