from typing import Dict

from django import template
from django.utils.safestring import mark_safe

from django_vite.core.asset_loader import DjangoViteAssetLoader, DEFAULT_APP_NAME


register = template.Library()


@register.simple_tag
@mark_safe
def vite_hmr_client(app: str = DEFAULT_APP_NAME, **kwargs: Dict[str, str]) -> str:
    """
    Generates the script tag for the Vite WS client for HMR.
    Only used in development, in production this method returns
    an empty string.

    Arguments:
        config {str} -- Configuration to use.

    Returns:
        str -- The script tag or an empty string.

    Keyword Arguments:
        **kwargs {Dict[str, str]} -- Adds new attributes to generated
            script tags.
    """

    return DjangoViteAssetLoader.instance().generate_vite_ws_client(app, **kwargs)


@register.simple_tag
@mark_safe
def vite_asset(
    path: str,
    app: str = DEFAULT_APP_NAME,
    **kwargs: Dict[str, str],
) -> str:
    """
    Generates a <script> tag for this JS/TS asset, a <link> tag for
    all of its CSS dependencies, and a <link rel="modulepreload">
    for all js dependencies, as listed in the manifest file
    In development Vite loads all by itself.

    Arguments:
        path {str} -- Path to a Vite JS/TS asset to include.
        config {str} -- Configuration to use.

    Returns:
        str -- All tags to import this file in your HTML page.

    Keyword Arguments:
        **kwargs {Dict[str, str]} -- Adds new attributes to generated
            script tags.

    Raises:
        RuntimeError: If cannot find the file path in the
            manifest (only in production).

    Returns:
        str -- The <script> tag and all <link> tags to import this
            asset in your page.
    """
    assert path is not None
    return DjangoViteAssetLoader.instance().generate_vite_asset(path, app, **kwargs)


@register.simple_tag
@mark_safe
def vite_preload_asset(path: str, app: str = DEFAULT_APP_NAME) -> str:
    """
    Generates preloadmodule tag for this JS/TS asset and preloads
    all of its CSS and JS dependencies by reading the manifest
    file (for production only).
    In development does nothing.

    Arguments:
        path {str} -- Path to a Vite JS/TS asset to include.

    Returns:
        str -- All tags to import this file in your HTML page.

    Raises:
        RuntimeError: If cannot find the file path in the
            manifest (only in production).

    """
    assert path is not None
    return DjangoViteAssetLoader.instance().preload_vite_asset(path, app)


@register.simple_tag
def vite_asset_url(path: str, app: str = DEFAULT_APP_NAME) -> str:
    """
    Generates only the URL of an asset managed by ViteJS.
    Warning, this function does not generate URLs for dependant assets.

    Arguments:
        path {str} -- Path to a Vite asset.
        config {str} -- Configuration to use.

    Raises:
        RuntimeError: If cannot find the asset path in the
            manifest (only in production).

    Returns:
        str -- The URL of this asset.
    """
    assert path is not None
    return DjangoViteAssetLoader.instance().generate_vite_asset_url(path, app)


@register.simple_tag
@mark_safe
def vite_legacy_polyfills(app: str = DEFAULT_APP_NAME, **kwargs: Dict[str, str]) -> str:
    """
    Generates a <script> tag to the polyfills generated
    by '@vitejs/plugin-legacy' if used.
    This tag must be included at end of the <body> before including
    other legacy scripts.

    Arguments:
        app {str} -- Configuration to use.

    Keyword Arguments:
        **kwargs {Dict[str, str]} -- Adds new attributes to generated
            script tags.

    Raises:
        RuntimeError: If polyfills path not found inside
            the 'manifest.json' (only in production).

    Returns:
        str -- The script tag to the polyfills.
    """
    return DjangoViteAssetLoader.instance().generate_vite_legacy_polyfills(
        app, **kwargs
    )


@register.simple_tag
@mark_safe
def vite_legacy_asset(
    path: str,
    app: str = DEFAULT_APP_NAME,
    **kwargs: Dict[str, str],
) -> str:
    """
    Generates a <script> tag for legacy assets JS/TS
    generated by '@vitejs/plugin-legacy'
    (in production only, in development do nothing).

    Arguments:
        path {str} -- Path to a Vite asset to include
            (must contains '-legacy' in its name).
        app {str} -- Configuration to use.

    Keyword Arguments:
        **kwargs {Dict[str, str]} -- Adds new attributes to generated
            script tags.

    Raises:
        RuntimeError: If cannot find the asset path in
            the manifest (only in production).

    Returns:
        str -- The script tag of this legacy asset.
    """

    assert path is not None

    return DjangoViteAssetLoader.instance().generate_vite_legacy_asset(
        path, app, **kwargs
    )


@register.simple_tag
@mark_safe
def vite_react_refresh(
    app: str = DEFAULT_APP_NAME,
    **kwargs: Dict[str, str],
) -> str:
    """
    Generates the script for the Vite React Refresh for HMR.
    Only used in development, in production this method returns
    an empty string.

    Keyword Arguments:
        **kwargs {Dict[str, str]} -- Adds new attributes to generated
            script tags.

    Returns:
        str -- The script or an empty string.
    """
    return DjangoViteAssetLoader.instance().generate_vite_react_refresh_url(
        app, **kwargs
    )
