from __future__ import annotations

import os
import shutil
import subprocess
from pathlib import Path

from tkpptx import (
    BackendUnavailableError,
    ExportError,
    ExportOptions,
    UnsupportedOperationError,
    resolve_page_range,
)


class OfficeCliBackend:
    name = "officecli"

    def __init__(self) -> None:
        self.executable = self._find_executable()

    @staticmethod
    def _find_executable() -> str | None:
        configured = os.environ.get("OFFICECLI_EXE")
        if configured and Path(configured).exists():
            return str(Path(configured).resolve())

        for candidate in ("officecli.exe", "officecli"):
            found = shutil.which(candidate)
            if found:
                return found
        return None

    def is_available(self) -> bool:
        return self.executable is not None

    def _run(self, command: list[str]) -> None:
        if not self.executable:
            raise BackendUnavailableError(
                "officecli was not found. Add it to PATH or set "
                "OFFICECLI_EXE to its full path."
            )

        completed = subprocess.run(
            [self.executable, *command],
            text=True,
            capture_output=True,
            check=False,
        )
        if completed.returncode != 0:
            details = "\n".join(
                part for part in (completed.stdout, completed.stderr) if part
            ).strip()
            raise ExportError(
                f"OfficeCLI failed with exit code "
                f"{completed.returncode}.\n{details}"
            )

    def export_pdf(
        self, input_path: Path, output_path: Path, options: ExportOptions
    ) -> Path:
        raise UnsupportedOperationError(
            "OfficeCLI PDF export requires an exporter plugin and is therefore "
            "not enabled in this backend. Use COM or LibreOffice."
        )

    def export_images(
        self, input_path: Path, output_dir: Path, options: ExportOptions
    ) -> list[Path]:
        start, end = resolve_page_range(input_path, options)
        outputs: list[Path] = []

        for page in range(start, end + 1):
            target = output_dir / f"slide_{page:03d}.png"
            if target.exists() and options.overwrite:
                target.unlink()

            command = [
                "view",
                str(input_path),
                "screenshot",
                "--start",
                str(page),
                "--end",
                str(page),
                "--screenshot-width",
                str(options.width),
                "--out",
                str(target),
            ]
            if options.render:
                command.extend(["--render", options.render])

            self._run(command)

            if not target.exists():
                raise ExportError(
                    f"OfficeCLI did not create slide image: {target}"
                )
            outputs.append(target)

        return outputs

    def export_html(
        self, input_path: Path, output_path: Path, options: ExportOptions
    ) -> Path:
        if output_path.exists() and options.overwrite:
            output_path.unlink()

        self._run(
            [
                "view",
                str(input_path),
                "html",
                "--out",
                str(output_path),
            ]
        )
        if not output_path.exists():
            raise ExportError(
                f"OfficeCLI did not create HTML output: {output_path}"
            )
        return output_path


def get_backend() -> OfficeCliBackend:
    return OfficeCliBackend()
