"""
LibreOffice screenshot capture functionality.

Handles template opening, PDF conversion, and PNG screenshot generation
for OOXML templates (.potx, .dotx, .xltx) using LibreOffice headless mode.
"""

import os
import subprocess
import tempfile
import time

import structlog
from typing import List, Dict, Any, Tuple, Optional
from pathlib import Path

try:
    from PIL import Image
except ImportError:
    Image = None

logger = structlog.get_logger(__name__)


def open_template_file(template_path: str) -> bool:
    """
    Open template file using LibreOffice headless mode.

    Args:
        template_path: Path to the template file.

    Returns:
        bool: True if template opened successfully, False otherwise.
    """
    try:
        # Validate template file exists
        if not Path(template_path).exists():
            logger.error("Template file does not exist", path=template_path)
            return False

        logger.info("Opening template file", path=template_path)

        # Use LibreOffice headless mode to open template
        cmd = ["libreoffice", "--headless", "--nologo", "--nolockcheck", template_path]

        result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)

        if result.returncode == 0:
            logger.info("Template opened successfully", path=template_path)
            return True
        else:
            logger.error(
                "Failed to open template",
                path=template_path,
                returncode=result.returncode,
                stderr=result.stderr,
            )
            return False

    except subprocess.TimeoutExpired:
        logger.error("Template opening timed out", path=template_path)
        return False
    except subprocess.CalledProcessError as e:
        logger.error("LibreOffice execution failed", error=str(e))
        return False
    except Exception as e:
        logger.error("Unexpected error opening template", error=str(e))
        return False


def convert_template_to_pdf(template_path: str, output_dir: str) -> bool:
    """
    Convert template file to PDF using LibreOffice.

    Args:
        template_path: Path to the template file.
        output_dir: Directory to save the PDF file.

    Returns:
        bool: True if conversion successful, False otherwise.
    """
    try:
        # Validate inputs
        if not Path(template_path).exists():
            logger.error("Template file does not exist", path=template_path)
            return False

        output_path = Path(output_dir)
        if not output_path.exists():
            output_path.mkdir(parents=True)

        logger.info(
            "Converting template to PDF", template=template_path, output=output_dir
        )

        # Use LibreOffice convert-to command
        cmd = [
            "libreoffice",
            "--headless",
            "--nologo",
            "--nolockcheck",
            "--convert-to",
            "pdf",
            "--outdir",
            output_dir,
            template_path,
        ]

        result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)

        if result.returncode == 0:
            logger.info("PDF conversion successful", template=template_path)
            return True
        else:
            logger.error(
                "PDF conversion failed",
                template=template_path,
                returncode=result.returncode,
                stderr=result.stderr,
            )
            return False

    except subprocess.TimeoutExpired:
        logger.error("PDF conversion timed out", template=template_path)
        return False
    except subprocess.CalledProcessError as e:
        logger.error("LibreOffice conversion failed", error=str(e))
        return False
    except Exception as e:
        logger.error("Unexpected error during PDF conversion", error=str(e))
        return False


def convert_pdf_to_png(pdf_path: str, png_path: str, dpi: int = 150) -> bool:
    """
    Convert PDF file to PNG screenshot.

    Args:
        pdf_path: Path to the PDF file.
        png_path: Path for the output PNG file.
        dpi: Resolution for PNG conversion.

    Returns:
        bool: True if conversion successful, False otherwise.
    """
    try:
        # Validate PDF file exists
        if not Path(pdf_path).exists():
            logger.error("PDF file does not exist", path=pdf_path)
            return False

        logger.info("Converting PDF to PNG", pdf=pdf_path, png=png_path, dpi=dpi)

        output_path = Path(png_path)
        output_path.parent.mkdir(parents=True, exist_ok=True)

        # Attempt conversion using LibreOffice first
        cmd = [
            "libreoffice",
            "--headless",
            "--nologo",
            "--nolockcheck",
            "--convert-to",
            "png",
            "--outdir",
            str(output_path.parent),
            pdf_path,
        ]
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            timeout=60,
        )

        if result.returncode == 0:
            generated_png = output_path.parent / f"{Path(pdf_path).stem}.png"
            if generated_png.exists():
                if generated_png != output_path:
                    generated_png.replace(output_path)
                logger.info(
                    "PNG conversion successful via LibreOffice", png=str(output_path)
                )
                return True

        # Fallback to Pillow if available
        if Image is None:
            logger.error("Pillow library not available for PNG conversion")
            return False

        image = Image.open(pdf_path)
        image.save(png_path, "PNG")

        logger.info("PNG conversion successful via Pillow", png=png_path)
        return True

    except ImportError:
        logger.error("Pillow library not available for PNG conversion")
        return False
    except Exception as e:
        logger.error("Error during PNG conversion", error=str(e), pdf=pdf_path)
        return False


def capture_template_screenshot(
    template_path: str, output_path: str, dpi: int = 150
) -> bool:
    """
    Capture screenshot of template by converting to PDF then PNG.

    Args:
        template_path: Path to the template file.
        output_path: Path for the output PNG screenshot.
        dpi: Resolution for screenshot.

    Returns:
        bool: True if screenshot captured successfully, False otherwise.
    """
    try:
        logger.info(
            "Starting template screenshot capture",
            template=template_path,
            output=output_path,
        )

        # Create temporary directory for PDF
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)

            # Step 1: Convert template to PDF
            if not convert_template_to_pdf(template_path, str(temp_path)):
                logger.error(
                    "Failed to convert template to PDF", template=template_path
                )
                return False

            # Find the generated PDF file
            template_name = Path(template_path).stem
            pdf_file = temp_path / f"{template_name}.pdf"

            if not pdf_file.exists():
                logger.error(
                    "PDF file not found after conversion", expected=str(pdf_file)
                )
                return False

            # Step 2: Convert PDF to PNG
            if not convert_pdf_to_png(str(pdf_file), output_path, dpi=dpi):
                logger.error("Failed to convert PDF to PNG", pdf=str(pdf_file))
                return False

            logger.info(
                "Template screenshot captured successfully",
                template=template_path,
                output=output_path,
            )
            return True

    except Exception as e:
        logger.error(
            "Unexpected error during screenshot capture",
            error=str(e),
            template=template_path,
        )
        return False


def process_template_tier(templates_dir: str, output_dir: str) -> bool:
    """
    Process all templates in a tier directory.

    Args:
        templates_dir: Directory containing template files.
        output_dir: Directory for screenshot outputs.

    Returns:
        bool: True if all templates processed successfully, False otherwise.
    """
    try:
        templates_path = Path(templates_dir)
        output_path = Path(output_dir)

        if not templates_path.exists():
            logger.error("Templates directory does not exist", path=templates_dir)
            return False

        # Create output directory
        output_path.mkdir(parents=True, exist_ok=True)

        logger.info(
            "Processing template tier", templates=templates_dir, output=output_dir
        )

        # Find all template files
        template_patterns = ["*.potx", "*.dotx", "*.xltx"]
        template_files = []

        for pattern in template_patterns:
            template_files.extend(templates_path.rglob(pattern))

        if not template_files:
            logger.warning("No template files found in tier", path=templates_dir)
            return True

        # Process each template
        all_successful = True
        for template_file in template_files:
            output_file = output_path / f"{template_file.stem}.png"

            if not capture_template_screenshot(str(template_file), str(output_file)):
                logger.error("Failed to process template", template=str(template_file))
                all_successful = False

        logger.info(
            "Template tier processing completed",
            templates=templates_dir,
            successful=all_successful,
        )

        return all_successful

    except Exception as e:
        logger.error(
            "Error processing template tier", error=str(e), templates=templates_dir
        )
        return False


def process_all_template_tiers(templates_base_dir: str, output_base_dir: str) -> bool:
    """
    Process all template tiers (community, professional, etc.).

    Args:
        templates_base_dir: Base directory containing tier subdirectories.
        output_base_dir: Base directory for screenshot outputs.

    Returns:
        bool: True if all tiers processed successfully, False otherwise.
    """
    try:
        base_path = Path(templates_base_dir)
        output_base = Path(output_base_dir)

        if not base_path.exists():
            logger.error(
                "Templates base directory does not exist", path=templates_base_dir
            )
            return False

        logger.info("Processing all template tiers", base=templates_base_dir)

        # Find tier directories
        tier_dirs = [d for d in base_path.iterdir() if d.is_dir()]

        if not tier_dirs:
            logger.warning("No tier directories found", path=templates_base_dir)
            return True

        all_successful = True
        for tier_dir in tier_dirs:
            tier_output = output_base / tier_dir.name

            if not process_template_tier(str(tier_dir), str(tier_output)):
                logger.error("Failed to process tier", tier=tier_dir.name)
                all_successful = False

        logger.info(
            "All template tiers processing completed", successful=all_successful
        )
        return all_successful

    except Exception as e:
        logger.error("Error processing all template tiers", error=str(e))
        return False


def capture_template_with_validation(template_path: str, output_path: str) -> bool:
    """
    Capture template screenshot with LibreOffice validation.

    Args:
        template_path: Path to the template file.
        output_path: Path for the output PNG file.

    Returns:
        bool: True if capture successful with validation, False otherwise.
    """
    try:
        logger.info("Starting template capture with validation", template=template_path)

        # Validate LibreOffice is available
        from .libreoffice_setup import validate_headless_mode

        if not validate_headless_mode():
            logger.error("LibreOffice headless validation failed")
            return False

        # Perform screenshot capture
        return capture_template_screenshot(template_path, output_path)

    except Exception as e:
        logger.error("Error during template capture with validation", error=str(e))
        return False


def capture_with_environment_setup(template_path: str, output_path: str) -> bool:
    """
    Capture template screenshot with environment setup validation.

    Args:
        template_path: Path to the template file.
        output_path: Path for the output PNG file.

    Returns:
        bool: True if capture successful with environment setup, False otherwise.
    """
    try:
        logger.info(
            "Starting template capture with environment setup", template=template_path
        )

        # Validate environment
        from .environment_setup import validate_github_environment

        if not validate_github_environment():
            logger.warning("GitHub environment validation failed, continuing anyway")

        # Perform screenshot capture
        return capture_template_screenshot(template_path, output_path)

    except Exception as e:
        logger.error(
            "Error during template capture with environment setup", error=str(e)
        )
        return False


def validate_github_actions_environment() -> bool:
    """
    Validate GitHub Actions environment for screenshot capture.

    Returns:
        bool: True if environment is valid, False otherwise.
    """
    try:
        required_vars = ["GITHUB_WORKSPACE", "GITHUB_REPOSITORY"]
        missing_vars = [var for var in required_vars if var not in os.environ]

        if missing_vars:
            logger.warning("Missing GitHub environment variables", missing=missing_vars)
            # Don't fail for missing vars, just log warning
            return True

        logger.info("GitHub Actions environment validated successfully")
        return True

    except Exception as e:
        logger.error("Error validating GitHub Actions environment", error=str(e))
        return False


def validate_libreoffice_availability() -> bool:
    """
    Validate that LibreOffice is available in the current environment.

    Returns:
        bool: True if LibreOffice is available, False otherwise.
    """
    try:
        result = subprocess.run(
            ["libreoffice", "--headless", "--version"],
            capture_output=True,
            text=True,
            timeout=15,
        )
        if result.returncode != 0:
            logger.error("LibreOffice check failed", stderr=result.stderr.strip())
            return False
        return True
    except FileNotFoundError:
        logger.error("LibreOffice executable not found in PATH")
        return False
    except Exception as e:
        logger.error("Error checking LibreOffice availability", error=str(e))
        return False


def capture_template_with_error_reporting(
    template_path: str, output_path: str
) -> Tuple[bool, Optional[str]]:
    """
    Capture template screenshot with detailed error reporting.

    Args:
        template_path: Path to the template file.
        output_path: Path for the output PNG file.

    Returns:
        Tuple of (success boolean, error details if failed).
    """
    try:
        logger.info(
            "Starting template capture with error reporting", template=template_path
        )

        result = capture_template_screenshot(template_path, output_path)

        if result:
            return True, None
        else:
            return False, "Screenshot capture failed - check logs for details"

    except subprocess.CalledProcessError as e:
        error_details = f"LibreOffice execution failed: {e}"
        logger.error("LibreOffice execution failed", error=error_details)
        return False, error_details
    except Exception as e:
        error_details = f"Unexpected error during screenshot capture: {e}"
        logger.error("Unexpected error during screenshot capture", error=error_details)
        return False, error_details


def process_all_template_tiers_with_retry(
    templates_base_dir: str, output_base_dir: str, max_retries: int = 2
) -> bool:
    """
    Process all template tiers with retry logic.

    Args:
        templates_base_dir: Base directory containing tier subdirectories.
        output_base_dir: Base directory for screenshot outputs.
        max_retries: Maximum number of retry attempts.

    Returns:
        bool: True if processing successful (possibly after retries), False otherwise.
    """
    try:
        logger.info(
            "Processing all template tiers with retry",
            base=templates_base_dir,
            retries=max_retries,
        )

        for attempt in range(max_retries + 1):
            logger.debug(
                "Processing attempt", attempt=attempt + 1, max_retries=max_retries + 1
            )

            result = process_all_template_tiers(templates_base_dir, output_base_dir)

            if result:
                logger.info("Template processing successful", attempt=attempt + 1)
                return True
            elif attempt < max_retries:
                logger.warning(
                    "Template processing failed, retrying", attempt=attempt + 1
                )
                time.sleep(5)  # Brief delay before retry
            else:
                logger.error("Template processing failed after all retries")

        return False

    except Exception as e:
        logger.error("Error during template processing with retry", error=str(e))
        return False


def run_github_actions_workflow() -> bool:
    """
    Run screenshot capture workflow in GitHub Actions context.

    Returns:
        bool: True if workflow completed successfully, False otherwise.
    """
    try:
        logger.info("Running GitHub Actions screenshot capture workflow")

        # Validate GitHub Actions environment
        if not validate_github_actions_environment():
            logger.error("GitHub Actions environment validation failed")
            return False

        # Get workspace paths from environment
        workspace = os.environ.get("GITHUB_WORKSPACE", "/github/workspace")
        templates_dir = f"{workspace}/templates"
        screenshots_dir = f"{workspace}/screenshots"

        # Process all templates
        return process_all_template_tiers(templates_dir, screenshots_dir)

    except Exception as e:
        logger.error("Error running GitHub Actions workflow", error=str(e))
        return False


def execute_matrix_strategy(
    matrix_config: Dict[str, List[str]], workspace_dir: str, output_dir: str
) -> List[Dict[str, Any]]:
    """
    Execute matrix strategy for template processing.

    Args:
        matrix_config: Matrix configuration with template types and tiers.
        workspace_dir: Base workspace directory.
        output_dir: Base output directory.

    Returns:
        List of execution results for each matrix combination.
    """
    try:
        logger.info("Executing matrix strategy", config=matrix_config)

        results: List[Dict[str, Any]] = []

        if not validate_libreoffice_availability():
            logger.error("LibreOffice not available for matrix execution")
            return results

        template_types = matrix_config.get("template-type", [])
        tiers = matrix_config.get("tier", [])

        workspace = Path(workspace_dir)
        output_root = Path(output_dir)
        output_root.mkdir(parents=True, exist_ok=True)

        templates_root = workspace / "templates"
        if not templates_root.exists():
            alt_root = workspace / "generated" / "templates"
            templates_root = alt_root if alt_root.exists() else templates_root

        if not templates_root.exists():
            logger.error("Templates root directory not found", path=str(templates_root))
            return results

        for template_type in template_types:
            extension = f".{template_type.lstrip('.')}"
            for tier in tiers:
                tier_dir = templates_root / tier
                if not tier_dir.exists():
                    logger.error(
                        "Tier directory missing", tier=tier, path=str(tier_dir)
                    )
                    results.append(
                        {
                            "template-type": template_type,
                            "tier": tier,
                            "status": "missing_tier",
                            "processed": 0,
                            "failed": 0,
                            "duration": 0,
                        }
                    )
                    continue

                template_files = list(tier_dir.rglob(f"*{extension}"))
                if not template_files:
                    results.append(
                        {
                            "template-type": template_type,
                            "tier": tier,
                            "status": "missing_templates",
                            "processed": 0,
                            "failed": 0,
                            "duration": 0,
                        }
                    )
                    continue

                start_time = time.time()
                failed = 0
                for template_path in template_files:
                    output_path = (
                        output_root / tier / template_type / f"{template_path.stem}.png"
                    )
                    output_path.parent.mkdir(parents=True, exist_ok=True)
                    if not capture_template_screenshot(
                        str(template_path), str(output_path)
                    ):
                        failed += 1
                duration = int(time.time() - start_time)

                status = "success" if failed == 0 else "failed"
                results.append(
                    {
                        "template-type": template_type,
                        "tier": tier,
                        "status": status,
                        "processed": len(template_files),
                        "failed": failed,
                        "duration": duration,
                    }
                )

        logger.info(
            "Matrix strategy execution completed", total_combinations=len(results)
        )

        return results

    except Exception as e:
        logger.error("Error executing matrix strategy", error=str(e))
        return []


def run_workflow_with_monitoring(templates_dir: str, output_dir: str) -> bool:
    """
    Run screenshot capture workflow with comprehensive monitoring.

    Args:
        templates_dir: Directory containing templates.
        output_dir: Directory for screenshot outputs.

    Returns:
        bool: True if workflow completed successfully, False otherwise.
    """
    try:
        start_time = time.time()

        logger.info(
            "Starting workflow with monitoring",
            templates=templates_dir,
            output=output_dir,
        )

        # Process templates with monitoring
        result = process_all_template_tiers(templates_dir, output_dir)

        end_time = time.time()
        duration = end_time - start_time

        logger.info(
            "Workflow with monitoring completed", success=result, duration=duration
        )

        return result

    except Exception as e:
        logger.error("Error during workflow with monitoring", error=str(e))
        return False
