"""
Enhanced Confluence Connector
A comprehensive Python connector for interacting with Confluence API
Supports reading, writing, and managing Confluence pages, spaces, and content
"""

import requests
import logging
import os
from typing import Dict, List, Any, Union
import time
import pytesseract
from PIL import Image, ImageEnhance
import io


class ConfluenceConnector:
    """
    Enhanced Confluence connector with comprehensive features for
    managing Confluence pages, spaces, attachments, and content
    """

    def __init__(
        self,
        confluence_url: str,
        token: str,
        verify_ssl: bool = True,
        max_retries: int = 3,
        cloud: bool = False,
    ):
        """
        Initialize Confluence connector

        Args:
            confluence_url: Base URL of Confluence instance
            token: API token for authentication
            username: Username for basic auth (optional for cloud, required for server)
            service: Service type for configuration
            timeout: Request timeout in seconds
            verify_ssl: Whether to verify SSL certificates
            max_retries: Maximum number of retry attempts
            cloud: Whether this is Atlassian Cloud instance
        """
        self.confluence_url = confluence_url.rstrip("/")
        self.token = token
        self.verify_ssl = verify_ssl
        self.max_retries = max_retries
        self.cloud = cloud
        self.timeout = 30

        # Setup logging
        self.logger = logging.getLogger("ConfluenceConnector")
        if not self.logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter(
                "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
            )
            handler.setFormatter(formatter)
            self.logger.addHandler(handler)
            self.logger.setLevel(logging.INFO)

        # Initialize session
        self.session = requests.Session()
        self._setup_authentication()

        # API endpoints
        if self.cloud:
            self.api_base = f"{self.confluence_url}/rest/api"
            self.logger.info("Confluence Cloud connector initialized")
        else:
            self.api_base = f"{self.confluence_url}/rest/api"
            self.logger.info("Confluence Server connector initialized")

    def _setup_authentication(self):
        """Setup authentication headers"""
        
        # Bearer token authentication
        self.session.headers.update(
            {
                "Authorization": f"Bearer {self.token}",
                "Accept": "application/json",
                "Content-Type": "application/json",
            }
        )
        self.logger.info("Using bearer token authentication")

    def _make_request(
        self, method: str, endpoint: str, **kwargs
    ) -> Union[Dict[str, Any], bytes]:
        """
        Make HTTP request with retry logic and error handling

        Args:
            method: HTTP method
            endpoint: API endpoint
            **kwargs: Additional request parameters

        Returns:
            Response data as dictionary or bytes
        """
        import time
        if endpoint.startswith("http"):
            url = endpoint  
        else:
            url = f"{self.api_base}/{endpoint.lstrip('/')}"

        for attempt in range(self.max_retries + 1):
            start_time = time.time()
            try:
                response = self.session.request(
                    method=method,
                    url=url,
                    timeout=self.timeout,
                    verify=self.verify_ssl,
                    **kwargs,
                )

                response.raise_for_status()

                # Check if response is binary content
                content_type = response.headers.get("Content-Type", "")
                if (
                    "image" in content_type
                    or "application/octet-stream" in content_type
                ):
                    end_time = time.time()
                    duration = end_time - start_time
                    self.logger.info(
                        f"API call to {url} (binary) took {duration:.2f}s"
                    )
                    return response.content
                elif "text" in content_type:
                    end_time = time.time()
                    duration = end_time - start_time
                    self.logger.info(
                        f"API call to {url} (text) took {duration:.2f}s"
                    )
                    return response.text

                end_time = time.time()
                duration = end_time - start_time
                self.logger.info(
                    f"API call to {url} (JSON) took {duration:.2f}s"
                )
                if response.content:
                    return response.json()
                else:
                    return {}

            except requests.exceptions.RequestException as e:
                if attempt == self.max_retries:
                    self.logger.error(
                        f"Request failed after {self.max_retries} attempts: {e}"
                    )
                    raise Exception(f"Failed to make request to {url}: {e}")

                wait_time = 2**attempt
                self.logger.warning(
                    f"Request failed (attempt {attempt + 1}), "
                    f"retrying in {wait_time}s: {e}"
                )
                time.sleep(wait_time)

    def test_connection(self) -> bool:
        """Test connection to Confluence"""
        try:
            self._make_request("GET", "/space")
            self.logger.info("Connection test successful")
            return True
        except Exception as e:
            self.logger.error(f"Connection test failed: {e}")
            return False

    # ==================== PAGE OPERATIONS ====================

    def get_page_by_id(self, page_id: str, expand: List[str] = None) -> Dict[str, Any]:
        """Get page by ID with optional expansions"""
        try:
            params = {}
            if expand:
                params["expand"] = ",".join(expand)

            response = self._make_request("GET", f"/content/{page_id}", params=params)
            return response

        except Exception as e:
            self.logger.error(f"Failed to get page {page_id}: {e}")
            raise

    def get_page_by_title(
        self, space_key: str, title: str, expand: List[str] = None
    ) -> Dict[str, Any]:
        """Get page by title in a specific space"""
        try:
            params = {"spaceKey": space_key, "title": title, "type": "page"}

            if expand:
                params["expand"] = ",".join(expand)

            response = self._make_request("GET", "/content", params=params)

            results = response.get("results", [])
            if not results:
                raise Exception(f"Page '{title}' not found in space '{space_key}'")

            return results[0]

        except Exception as e:
            self.logger.error(
                f"Failed to get page '{title}' in space '{space_key}': {e}"
            )
            raise

    def get_page_content(self, page_id: str, content_format: str = "storage") -> str:
        """Get page content in specified format"""
        try:
            page = self.get_page_by_id(page_id, expand=[f"body.{content_format}"])
            content = page.get("body", {}).get(content_format, {}).get("value", "")
            return content

        except Exception as e:
            self.logger.error(f"Failed to get content for page {page_id}: {e}")
            raise

    def create_page(
        self,
        space_key: str,
        title: str,
        content: str,
        parent_id: str = None,
        content_format: str = "storage",
    ) -> Dict[str, Any]:
        """Create a new page"""
        try:
            payload = {
                "type": "page",
                "title": title,
                "space": {"key": space_key},
                "body": {
                    "storage": {"value": content, "representation": content_format}
                },
            }

            if parent_id:
                payload["ancestors"] = [{"id": parent_id}]

            response = self._make_request("POST", "/content", json=payload)
            self.logger.info(
                f"Created page '{title}' in space '{space_key}' "
                f"(ID: {response.get('id')})"
            )
            return response

        except Exception as e:
            self.logger.error(f"Failed to create page '{title}': {e}")
            raise

    def update_page(
        self,
        page_id: str,
        title: str = None,
        content: str = None,
        content_format: str = "storage",
        minor_edit: bool = False,
    ) -> Dict[str, Any]:
        """Update an existing page"""
        try:
            current_page = self.get_page_by_id(
                page_id, expand=["body.storage", "version", "space"]
            )

            payload = {
                "id": page_id,
                "type": "page",
                "title": title if title else current_page.get("title"),
                "space": {"key": current_page.get("space", {}).get("key")},
                "version": {
                    "number": current_page.get("version", {}).get("number", 0) + 1,
                    "minorEdit": minor_edit,
                },
            }

            if content:
                payload["body"] = {
                    "storage": {"value": content, "representation": content_format}
                }
            else:
                payload["body"] = current_page.get("body", {})

            response = self._make_request("PUT", f"/content/{page_id}", json=payload)
            self.logger.info(
                f"Updated page {page_id} (version {payload['version']['number']})"
            )
            return response

        except Exception as e:
            self.logger.error(f"Failed to update page {page_id}: {e}")
            raise

    def copy_page(
        self,
        page_id: str,
        destination_page_id: str = None,
        space_key: str = None,
        title: str = None,
    ) -> Dict[str, Any]:
        """Copy a page to a new location"""
        try:
            source_page = self.get_page_by_id(page_id, expand=["body.storage", "space"])

            dest_space = (
                space_key if space_key else source_page.get("space", {}).get("key")
            )
            new_title = title if title else f"Copy of {source_page.get('title')}"
            content = source_page.get("body", {}).get("storage", {}).get("value", "")

            return self.create_page(
                space_key=dest_space,
                title=new_title,
                content=content,
                parent_id=destination_page_id,
            )

        except Exception as e:
            self.logger.error(f"Failed to copy page {page_id}: {e}")
            raise

    # ==================== ATTACHMENT OPERATIONS ====================

    def get_page_attachments(self, page_id: str) -> List[Dict[str, Any]]:
        """Get all attachments for a page"""
        try:
            response = self._make_request("GET", f"/content/{page_id}/child/attachment")
            return response.get("results", [])

        except Exception as e:
            self.logger.error(f"Failed to get attachments for page {page_id}: {e}")
            raise

    def upload_attachment(
        self, page_id: str, file_path: str, comment: str = None
    ) -> Dict[str, Any]:
        """Upload an attachment to a page"""
        try:
            if not os.path.exists(file_path):
                raise FileNotFoundError(f"File not found: {file_path}")

            url = f"{self.api_base}/content/{page_id}/child/attachment"

            with open(file_path, "rb") as f:
                files = {"file": (os.path.basename(file_path), f)}
                data = {}
                if comment:
                    data["comment"] = comment

                # Remove Content-Type header for multipart/form-data
                headers = dict(self.session.headers)
                headers.pop("Content-Type", None)

                response = self.session.post(
                    url,
                    files=files,
                    data=data,
                    headers=headers,
                    timeout=self.timeout,
                    verify=self.verify_ssl,
                )

                response.raise_for_status()
                result = response.json()

                self.logger.info(
                    f"Uploaded attachment '{os.path.basename(file_path)}' "
                    f"to page {page_id}"
                )
                return result.get("results", [{}])[0]

        except Exception as e:
            self.logger.error(f"Failed to upload attachment: {e}")
            raise

    def download_attachment(
        self, attachment_url: str, save_path: str = None
    ) -> Union[bytes, str]:
        """Download an attachment"""
        try:
            if not attachment_url.startswith("http"):
                attachment_url = f"{self.confluence_url}{attachment_url}"

            content = self._make_request("GET", attachment_url)

            if save_path:
                os.makedirs(os.path.dirname(save_path), exist_ok=True)

                with open(save_path, "wb") as f:
                    f.write(content)

                self.logger.info(f"Attachment saved to {save_path}")
                return save_path

            return content

        except Exception as e:
            self.logger.error(f"Failed to download attachment: {e}")
            raise

    # ==================== COMMENT OPERATIONS ====================

    def add_comment(self, page_id: str, comment: str) -> Dict[str, Any]:
        """Add a comment to a page"""
        try:
            payload = {
                "type": "comment",
                "container": {"id": page_id, "type": "page"},
                "body": {"storage": {"value": comment, "representation": "storage"}},
            }

            response = self._make_request("POST", "/content", json=payload)
            self.logger.info(f"Added comment to page {page_id}")
            return response

        except Exception as e:
            self.logger.error(f"Failed to add comment: {e}")
            raise

    def get_page_comments(self, page_id: str) -> List[Dict[str, Any]]:
        """Get all comments for a page"""
        try:
            response = self._make_request("GET", f"/content/{page_id}/child/comment")
            return response.get("results", [])

        except Exception as e:
            self.logger.error(f"Failed to get comments: {e}")
            raise

    # ==================== LABEL OPERATIONS ====================

    def get_page_labels(self, page_id: str) -> List[str]:
        """Get labels for a page"""
        try:
            response = self._make_request("GET", f"/content/{page_id}/label")
            labels = [label.get("name") for label in response.get("results", [])]
            return labels

        except Exception as e:
            self.logger.error(f"Failed to get labels: {e}")
            raise

    def add_labels(self, page_id: str, labels: List[str]) -> Dict[str, Any]:
        """Add labels to a page"""
        try:
            payload = [{"prefix": "global", "name": label} for label in labels]
            response = self._make_request(
                "POST", f"/content/{page_id}/label", json=payload
            )
            self.logger.info(f"Added {len(labels)} labels to page {page_id}")
            return response

        except Exception as e:
            self.logger.error(f"Failed to add labels: {e}")
            raise

    def remove_label(self, page_id: str, label: str) -> bool:
        """Remove a label from a page"""
        try:
            self._make_request("DELETE", f"/content/{page_id}/label/{label}")
            self.logger.info(f"Removed label '{label}' from page {page_id}")
            return True

        except Exception as e:
            self.logger.error(f"Failed to remove label: {e}")
            raise

    # ==================== SPACE OPERATIONS ====================

    def get_space(self, space_key: str, expand: List[str] = None) -> Dict[str, Any]:
        """Get space information"""
        try:
            params = {}
            if expand:
                params["expand"] = ",".join(expand)

            response = self._make_request("GET", f"/space/{space_key}", params=params)
            return response

        except Exception as e:
            self.logger.error(f"Failed to get space {space_key}: {e}")
            raise

    def get_space_pages(
        self, space_key: str, limit: int = 25, start: int = 0
    ) -> List[Dict[str, Any]]:
        """Get all pages in a space"""
        try:
            params = {
                "spaceKey": space_key,
                "type": "page",
                "limit": limit,
                "start": start,
            }

            response = self._make_request("GET", "/content", params=params)
            return response.get("results", [])

        except Exception as e:
            self.logger.error(f"Failed to get pages for space {space_key}: {e}")
            raise

    def get_all_spaces(self, limit: int = 25) -> List[Dict[str, Any]]:
        """Get all spaces"""
        try:
            params = {"limit": limit}
            response = self._make_request("GET", "/space", params=params)
            return response.get("results", [])

        except Exception as e:
            self.logger.error(f"Failed to get spaces: {e}")
            raise

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

    def search_content(
        self, cql: str, limit: int = 25, start: int = 0
    ) -> List[Dict[str, Any]]:
        """Search content using CQL"""
        try:
            params = {"cql": cql, "limit": limit, "start": start}

            response = self._make_request("GET", "/content/search", params=params)
            return response.get("results", [])

        except Exception as e:
            self.logger.error(f"Failed to search with CQL: {e}")
            raise

    # ==================== HISTORY & VERSION OPERATIONS ====================

    def get_page_history(self, page_id: str, limit: int = 25) -> List[Dict[str, Any]]:
        """Get page version history"""
        try:
            params = {"limit": limit}
            response = self._make_request(
                "GET", f"/content/{page_id}/history", params=params
            )
            return response.get("results", [])

        except Exception as e:
            self.logger.error(f"Failed to get history: {e}")
            raise

    def get_page_children(
        self, page_id: str, expand: List[str] = None
    ) -> List[Dict[str, Any]]:
        """Get child pages of a page"""
        try:
            params = {}
            if expand:
                params["expand"] = ",".join(expand)

            response = self._make_request(
                "GET", f"/content/{page_id}/child/page", params=params
            )
            return response.get("results", [])

        except Exception as e:
            self.logger.error(f"Failed to get children: {e}")
            raise

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

    def batch_get_pages(self, page_ids: List[str]) -> List[Dict[str, Any]]:
        """Get multiple pages in batch"""
        results = []
        for page_id in page_ids:
            try:
                page = self.get_page_by_id(page_id)
                results.append(page)
            except Exception as e:
                self.logger.warning(f"Failed to get page {page_id}: {e}")
                results.append({"id": page_id, "error": str(e)})

        return results

    def batch_update_labels(
        self, page_ids: List[str], labels: List[str]
    ) -> Dict[str, Any]:
        """Add labels to multiple pages"""
        results = {"success": [], "failed": []}

        for page_id in page_ids:
            try:
                self.add_labels(page_id, labels)
                results["success"].append(page_id)
            except Exception as e:
                self.logger.warning(f"Failed to add labels to page {page_id}: {e}")
                results["failed"].append({"page_id": page_id, "error": str(e)})

        return results

    # ==================== UTILITY METHODS ====================

    def extract_text_from_page(
        self, page_id: str, include_metadata: bool = False
    ) -> Dict[str, Any]:
        """Extract plain text from page content"""
        try:
            page = self.get_page_by_id(
                page_id, expand=["body.storage", "version", "space"]
            )
            content = page.get("body", {}).get("storage", {}).get("value", "")

            # Basic HTML tag removal
            import re

            text = re.sub(r"<[^>]+>", "", content)
            text = re.sub(r"\s+", " ", text).strip()

            result = {"text": text}

            if include_metadata:
                result["metadata"] = {
                    "title": page.get("title"),
                    "space": page.get("space", {}).get("key"),
                    "version": page.get("version", {}).get("number"),
                    "lastModified": page.get("version", {}).get("when"),
                    "url": (
                        f"{self.confluence_url}/pages/viewpage.action?pageId={page_id}"
                    ),
                }

            return result

        except Exception as e:
            self.logger.error(f"Failed to extract text: {e}")
            raise

    def explain_attachment(self, page_id: str, attachment_title: str) -> str:
        """Download and explain the content of an attachment"""
        try:
            attachments = self.get_page_attachments(page_id)
            for att in attachments:
                if att.get('title') == attachment_title:
                    download_url = att.get('_links', {}).get('download')
                    if download_url:
                        base_url = self.confluence_url
                        direct_url = base_url + download_url
                        content = self._make_request("GET", direct_url)
                        media_type = att.get('extensions', {}).get('mediaType', '')
                        
                        # Handle Gliffy diagrams
                        if media_type == 'application/gliffy+json':
                            if isinstance(content, dict):
                                return self._parse_gliffy(content)
                            else:
                                msg = "Error: Gliffy content is not in "
                                msg += "expected JSON format"
                                return msg
                        
                        # Handle images with OCR
                        elif media_type.startswith('image/'):
                            if isinstance(content, bytes):
                                try:
                                    image = Image.open(io.BytesIO(content))
                                    
                                    # Extract metadata
                                    metadata = f"Image dimensions: {image.size[0]}x{image.size[1]}\n"
                                    metadata += f"Image format: {image.format}\n"
                                    metadata += f"Color mode: {image.mode}\n\n"
                                    
                                    # Preprocessing for better OCR
                                    # Convert to grayscale if not already
                                    if image.mode != 'L':
                                        image = image.convert('L')
                                    
                                    # Enhance contrast for better text recognition
                                    enhancer = ImageEnhance.Contrast(image)
                                    image = enhancer.enhance(1.5)  # Moderate contrast enhancement
                                    
                                    text = pytesseract.image_to_string(image)
                                    
                                    if text.strip():
                                        result = f"## Image Analysis\n\n{metadata}"
                                        result += f"### Extracted Text (OCR)\n\n{text.strip()}"
                                        return result
                                    else:
                                        result = f"## Image Analysis\n\n{metadata}"
                                        result += f"### OCR Result\n\n"
                                        result += f"No readable text detected. The image may contain "
                                        result += f"diagrams, charts, or non-text content."
                                        return result
                                except Exception as ocr_error:
                                    # Fallback: try to get basic metadata even if OCR fails
                                    try:
                                        image = Image.open(io.BytesIO(content))
                                        metadata = f"Image dimensions: {image.size[0]}x{image.size[1]}\n"
                                        metadata += f"Image format: {image.format}\n"
                                        metadata += f"Color mode: {image.mode}\n\n"
                                        return (
                                            f"## Image Analysis\n\n{metadata}"
                                            f"### OCR Error\n\n"
                                            f"Image processing failed: {ocr_error}"
                                        )
                                    except Exception as meta_error:
                                        return (
                                            f"Image file detected but both OCR and metadata "
                                            f"extraction failed: {meta_error}"
                                        )
                            else:
                                msg = "Error: Image content is not in "
                                msg += "expected binary format"
                                return msg
                        
                        # Handle text files
                        elif media_type.startswith('text/'):
                            if isinstance(content, str):
                                # Check if content is a Mermaid diagram
                                content_stripped = content.strip()
                                mermaid_keywords = ('graph', 'flowchart', 'sequenceDiagram', 
                                                  'classDiagram', 'stateDiagram', 'erDiagram', 
                                                  'pie', 'gantt', 'journey')
                                if content_stripped and content_stripped.split('\n')[0].strip().lower().startswith(mermaid_keywords):
                                    return self._parse_mermaid(content)
                                else:
                                    return f"## Text Content\n\n```\n{content}\n```"
                            else:
                                msg = "Error: Text content is not in "
                                msg += "expected string format"
                                return msg
                        
                        # Handle PDF files
                        elif media_type == 'application/pdf':
                            msg = "PDF file detected. PDF parsing requires "
                            msg += "additional libraries (PyPDF2 or pdfplumber). "
                            msg += "Content cannot be extracted with current "
                            msg += "dependencies."
                            return msg
                        
                        # Handle Office documents
                        elif media_type in [
                            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                            'application/vnd.openxmlformats-officedocument.presentationml.presentation',
                            'application/msword',
                            'application/vnd.ms-excel',
                            'application/vnd.ms-powerpoint'
                        ]:
                            msg = f"Office document detected ({media_type}). "
                            msg += "Parsing requires additional libraries "
                            msg += "(python-docx, openpyxl, etc.). Content "
                            msg += "cannot be extracted with current dependencies."
                            return msg
                        
                        # Unsupported types
                        else:
                            msg = f"Unsupported content type: {media_type}. "
                            msg += "Supported types: Gliffy diagrams "
                            msg += "(application/gliffy+json), Images (image/*), "
                            msg += "Text files (text/*), Mermaid diagrams (text/* with Mermaid syntax)"
                            return msg
                    else:
                        return "Download URL not found for this attachment"
            return f"Attachment '{attachment_title}' not found on this page"
        except Exception as e:
            self.logger.error(f"Error explaining attachment: {e}")
            return f"Error explaining attachment: {str(e)}"

    def explain_all_attachments(self, page_id: str) -> Dict[str, str]:
        """Explain all supported attachments on a page"""
        explanations = {}
        attachments = self.get_page_attachments(page_id)
        for att in attachments:
            title = att.get('title')
            media_type = att.get('extensions', {}).get('mediaType', '')
            if (media_type == 'application/gliffy+json' or
                media_type.startswith('image/') or
                media_type.startswith('text/')):
                try:
                    explanation = self.explain_attachment(page_id, title)
                    explanations[title] = explanation
                except Exception as e:
                    explanations[title] = f"Error: {e}"
        return explanations

    def _parse_gliffy(self, gliffy_data: dict) -> str:
        """Parse Gliffy diagram JSON to describe the diagram"""
        import re
        from html import unescape
        
        if 'stage' in gliffy_data:
            content = gliffy_data['stage']
        else:
            content = gliffy_data.get('content', {})
        
        objects = content.get('objects', [])
        shapes = []
        connections = []
        uid_to_info = {}
        
        # First pass: collect all shapes with their text
        for obj in objects:
            uid = obj.get('id', obj.get('uid'))
            graphic = obj.get('graphic', {})
            
            if graphic.get('type') == 'Shape':
                shape_data = graphic.get('Shape', {})
                text_data = shape_data.get('text', {})
                text_html = text_data.get('html', '')
                
                # Extract text from HTML
                text = re.sub(r'<[^>]+>', '', text_html)
                text = unescape(text).strip()
                
                # Fallback to plain text if HTML text is empty
                if not text:
                    text = text_data.get('plain', '').strip()
                
                # Get shape type
                shape_tid = shape_data.get('tid', 'unknown')
                
                # Store shape info
                uid_to_info[uid] = {
                    'text': text,
                    'type': shape_tid,
                    'x': obj.get('x', 0),
                    'y': obj.get('y', 0)
                }
                
                if text:
                    shapes.append(f"- **{text}** ({shape_tid})")
                else:
                    shapes.append(f"- Shape {uid} ({shape_tid})")
        
        # Second pass: collect connections
        for obj in objects:
            graphic = obj.get('graphic', {})
            
            if graphic.get('type') == 'Line':
                start_obj = obj.get('start', {})
                start_ref = (
                    start_obj.get('ref') or
                    start_obj.get('id') or
                    start_obj.get('uid')
                )
                
                end_obj = obj.get('end', {})
                end_ref = (
                    end_obj.get('ref') or
                    end_obj.get('id') or
                    end_obj.get('uid')
                )
                
                start_info = uid_to_info.get(start_ref, {})
                end_info = uid_to_info.get(end_ref, {})
                
                start_text = start_info.get('text') or f"Shape {start_ref}"
                end_text = end_info.get('text') or f"Shape {end_ref}"
                
                if start_ref and end_ref:
                    connections.append(f"- {start_text} → {end_text}")
        
        # Build explanation
        explanation_parts = []
        
        if shapes:
            explanation_parts.append("## Diagram Components\n")
            explanation_parts.append("\n".join(shapes))
        
        if connections:
            explanation_parts.append("\n\n## Flow Connections\n")
            explanation_parts.append("\n".join(connections))
        
        if not shapes and not connections:
            return "No diagram elements found or unable to parse diagram structure."
        
        return "\n".join(explanation_parts)

    def _parse_mermaid(self, mermaid_content: str) -> str:
        """
        Parse Mermaid diagram text and provide explanation
        
        Args:
            mermaid_content: The Mermaid diagram text
            
        Returns:
            Explanation of the Mermaid diagram
        """
        lines = [line.strip() for line in mermaid_content.split('\n') if line.strip()]
        
        if not lines:
            return "Empty Mermaid diagram content."
        
        # Determine diagram type
        first_line = lines[0].lower()
        diagram_type = "unknown"
        
        if first_line.startswith('graph'):
            diagram_type = "graph/flowchart"
        elif first_line.startswith('flowchart'):
            diagram_type = "flowchart"
        elif first_line.startswith('sequencediagram'):
            diagram_type = "sequence diagram"
        elif first_line.startswith('classdiagram'):
            diagram_type = "class diagram"
        elif first_line.startswith('statediagram'):
            diagram_type = "state diagram"
        elif first_line.startswith('erDiagram'):
            diagram_type = "entity relationship diagram"
        elif first_line.startswith('pie'):
            diagram_type = "pie chart"
        elif first_line.startswith('gantt'):
            diagram_type = "gantt chart"
        elif first_line.startswith('journey'):
            diagram_type = "user journey"
        
        explanation = f"## Mermaid {diagram_type.title()} Diagram\n\n"
        explanation += f"This is a Mermaid {diagram_type} diagram containing:\n\n"
        
        # Basic analysis
        nodes = set()
        connections = []
        
        for line in lines[1:]:  # Skip first line
            line = line.strip()
            if not line or line.startswith('%%'):
                continue
                
            # Extract nodes and connections based on common patterns
            if '-->' in line or '---' in line or '->' in line:
                # Connection line
                connections.append(line)
                # Extract node names
                parts = line.replace('-->', '').replace('---', '').replace('->', '').split()
                for part in parts:
                    part = part.strip('[]()')
                    if part and not part.isdigit():
                        nodes.add(part)
            elif '[' in line and ']' in line:
                # Node definition
                node_match = line.split('[')[0].strip()
                if node_match:
                    nodes.add(node_match)
            elif line and not line[0].isdigit() and 'subgraph' not in line.lower():
                # Potential node name
                potential_node = line.split()[0].strip('[]()"')
                if potential_node and len(potential_node) > 1:
                    nodes.add(potential_node)
        
        explanation += f"- **{len(nodes)} nodes/elements**: "
        node_list = ', '.join(list(nodes)[:10])
        if len(nodes) > 10:
            node_list += '...'
        explanation += f"{node_list}\n"
        explanation += f"- **{len(connections)} connections/relationships**\n\n"
        
        if diagram_type in ["graph", "flowchart"]:
            explanation += "### Diagram Structure\n"
            explanation += "This flowchart represents a process or system flow "
            explanation += "with the following components:\n\n"
            explanation += "- **Nodes**: Represent states, actions, or decisions\n"
            explanation += "- **Connections**: Show the flow between nodes\n\n"
        elif diagram_type == "sequence diagram":
            explanation += "### Diagram Structure\n"
            explanation += "This sequence diagram shows interactions between "
            explanation += "different actors/components over time:\n\n"
            explanation += "- **Participants**: Entities involved in the interactions\n"
            explanation += "- **Messages**: Communications between participants\n\n"
        elif diagram_type == "class diagram":
            explanation += "### Diagram Structure\n"
            explanation += "This class diagram represents the structure of a system:\n\n"
            explanation += "- **Classes**: System components with attributes and methods\n"
            explanation += "- **Relationships**: Associations between classes\n\n"
        
        explanation += "### Raw Mermaid Code\n"
        explanation += "```\n" + mermaid_content + "\n```"
        
        return explanation

    def close(self):
        """Close the session"""
        if self.session:
            self.session.close()
            self.logger.info("Confluence connector session closed")
