from __future__ import annotations

from docutils import nodes
from sphinx.application import Sphinx
from sphinx.util.docutils import SphinxDirective, SphinxRole
from sphinx.util.typing import ExtensionMetadata
from sphinx.directives.code import LiteralInclude, container_wrapper

import requests
from requests.exceptions import RequestException
from docutils.parsers.rst import directives

class ExtInclude(LiteralInclude):
    """A directive to include code that comes from an url

    Sample use::

        .. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_010/firefox/00-proxy.yml
           :linenos:
           :language: yaml
           :caption: this is a interesting code

    - parameter required
    - linenos, language and caption are optionnal.

    :default language: yaml
    :default caption: extinclude parameter (url)

    """

    def run(self) -> list[nodes.Node]:
        url = self.arguments[0]
        
        try:
            headers = {
                'accept': 'application/text',
                'Content-Type': 'application/text',
            }
            response = requests.get(url, headers=headers)
            response.raise_for_status()  # This will raise an exception for 4xx/5xx status codes
            
        except requests.exceptions.HTTPError as e:
            if response.status_code == 404:
                error_msg = f"extinclude: URL not found (404): {url}"
            else:
                error_msg = f"extinclude: HTTP error {response.status_code}: {url}"
            
            # Create an error node that will be displayed in the documentation
            error_node = nodes.error()
            para = nodes.paragraph()
            para += nodes.Text(error_msg)
            error_node += para
            self.state.document.reporter.warning(error_msg, line=self.lineno)
            return [error_node]
            
        except requests.exceptions.RequestException as e:
            error_msg = f"extinclude: Failed to fetch URL {url}: {str(e)}"
            
            # Create an error node that will be displayed in the documentation
            error_node = nodes.error()
            para = nodes.paragraph()
            para += nodes.Text(error_msg)
            error_node += para
            self.state.document.reporter.warning(error_msg, line=self.lineno)
            return [error_node]

        code = response.text

        literal = nodes.literal_block(code, code)
        if 'language' in self.options:
            literal['language'] = self.options['language']
        else:
            literal['language'] = 'yaml'
        literal['linenos'] = 'linenos' in self.options
        if 'caption' in self.options:
            caption = self.options.get('caption')
        else:
            caption = url
        literal['caption'] = caption
        if 'name' in self.options:
            literal['name'] = self.options.get('name')
        literal = container_wrapper(self, literal, caption)
        self.add_name(literal)

        return [literal]


def setup(app: Sphinx) -> ExtensionMetadata:
    app.add_directive('extinclude', ExtInclude)

    return {
        'version': '0.1',
        'parallel_read_safe': True,
        'parallel_write_safe': True,
    }
