"""
Utilities for HTMX integration in Django views.

This module provides helper functions for creating standardized HTMX responses
with consistent patterns for success, error, and redirect handling.

Usage Examples:
    Success with toast:
        return htmx_success('Park saved successfully!')

    Error with message:
        return htmx_error('Validation failed', status=422)

    Redirect with message:
        return htmx_redirect_with_message('/parks/', 'Park created!')

    Close modal and refresh:
        return htmx_modal_close(refresh_target='#park-list')
"""

from __future__ import annotations

import json
from functools import wraps
from typing import TYPE_CHECKING, Any

from django.http import HttpResponse
from django.template import TemplateDoesNotExist
from django.template.loader import render_to_string

if TYPE_CHECKING:
    from django.http import HttpRequest


def _resolve_context_and_template(resp, default_template):
    """Extract context and template from view response."""
    context = {}
    template_name = default_template
    if isinstance(resp, tuple):
        if len(resp) >= 1:
            context = resp[0]
        if len(resp) >= 2 and resp[1]:
            template_name = resp[1]
    return context, template_name


def _render_htmx_or_full(request, template_name, context):
    """Try to render HTMX partial, fallback to full template."""
    if request.headers.get("HX-Request") == "true":
        partial = template_name.replace(".html", "_partial.html")
        try:
            return render_to_string(partial, context, request=request)
        except TemplateDoesNotExist:
            # Fall back to full template
            return render_to_string(template_name, context, request=request)
    return render_to_string(template_name, context, request=request)


def htmx_partial(template_name):
    """Decorator for view functions to render partials for HTMX requests.

    If the request is an HTMX request and a partial template exists with
    the convention '<template_name>_partial.html', that template will be
    rendered. Otherwise the provided template_name is used.
    """

    def decorator(view_func):
        @wraps(view_func)
        def _wrapped(request, *args, **kwargs):
            resp = view_func(request, *args, **kwargs)
            # If the view returned an HttpResponse, pass through
            if isinstance(resp, HttpResponse):
                return resp

            # Expecting a tuple (context, template_name) or (context,)
            context, tpl = _resolve_context_and_template(resp, template_name)
            html = _render_htmx_or_full(request, tpl, context)
            return HttpResponse(html)

        return _wrapped

    return decorator


def htmx_redirect(url: str) -> HttpResponse:
    """Create a response that triggers a client-side redirect via HTMX."""
    resp = HttpResponse("")
    resp["HX-Redirect"] = url
    return resp


def htmx_trigger(name: str, payload: dict | None = None) -> HttpResponse:
    """Create a response that triggers a client-side event via HTMX."""
    resp = HttpResponse("")
    if payload is None:
        resp["HX-Trigger"] = name
    else:
        resp["HX-Trigger"] = json.dumps({name: payload})
    return resp


def htmx_refresh() -> HttpResponse:
    """Create a response that triggers a client-side page refresh via HTMX."""
    resp = HttpResponse("")
    resp["HX-Refresh"] = "true"
    return resp


def htmx_swap_oob(target_id: str, html: str) -> HttpResponse:
    """Return an out-of-band swap response by wrapping HTML and setting headers.

    Note: For simple use cases this returns an HttpResponse containing the
    fragment; consumers should set `HX-Boost` headers when necessary.
    """
    resp = HttpResponse(html)
    resp["HX-Trigger"] = f"oob:{target_id}"
    return resp


# =============================================================================
# Standardized HTMX Response Helpers
# =============================================================================


def htmx_success(
    message: str,
    html: str = "",
    toast_type: str = "success",
    duration: int = 5000,
    title: str | None = None,
    action: dict[str, Any] | None = None,
) -> HttpResponse:
    """
    Create a standardized success response with toast notification.

    Args:
        message: Success message to display
        html: Optional HTML content for the response body
        toast_type: Toast type (success, info, warning)
        duration: Toast display duration in ms (0 for persistent)
        title: Optional toast title
        action: Optional action button {label: str, onClick: str}

    Returns:
        HttpResponse with HX-Trigger header for toast

    Examples:
        return htmx_success('Park saved successfully!')

        return htmx_success(
            'Item deleted',
            action={'label': 'Undo', 'onClick': 'undoDelete()'}
        )
    """
    resp = HttpResponse(html)
    toast_data: dict[str, Any] = {
        "type": toast_type,
        "message": message,
        "duration": duration,
    }
    if title:
        toast_data["title"] = title
    if action:
        toast_data["action"] = action

    resp["HX-Trigger"] = json.dumps({"showToast": toast_data})
    return resp


def htmx_error(
    message: str,
    html: str = "",
    status: int = 400,
    duration: int = 0,
    title: str | None = None,
    show_retry: bool = False,
) -> HttpResponse:
    """
    Create a standardized error response with toast notification.

    Args:
        message: Error message to display
        html: Optional HTML content for the response body
        status: HTTP status code (default: 400)
        duration: Toast display duration in ms (0 for persistent)
        title: Optional toast title
        show_retry: Whether to show a retry action

    Returns:
        HttpResponse with HX-Trigger header for error toast

    Examples:
        return htmx_error('Validation failed. Please check your input.')

        return htmx_error('Server error', status=500, show_retry=True)
    """
    resp = HttpResponse(html, status=status)
    toast_data: dict[str, Any] = {
        "type": "error",
        "message": message,
        "duration": duration,
    }
    if title:
        toast_data["title"] = title
    if show_retry:
        toast_data["action"] = {"label": "Retry", "onClick": "location.reload()"}

    resp["HX-Trigger"] = json.dumps({"showToast": toast_data})
    return resp


def htmx_warning(
    message: str,
    html: str = "",
    duration: int = 8000,
    title: str | None = None,
) -> HttpResponse:
    """
    Create a standardized warning response with toast notification.

    Args:
        message: Warning message to display
        html: Optional HTML content for the response body
        duration: Toast display duration in ms
        title: Optional toast title

    Returns:
        HttpResponse with HX-Trigger header for warning toast

    Examples:
        return htmx_warning('Your session will expire in 5 minutes.')
    """
    resp = HttpResponse(html)
    toast_data: dict[str, Any] = {
        "type": "warning",
        "message": message,
        "duration": duration,
    }
    if title:
        toast_data["title"] = title

    resp["HX-Trigger"] = json.dumps({"showToast": toast_data})
    return resp


def htmx_redirect_with_message(
    url: str,
    message: str,
    toast_type: str = "success",
) -> HttpResponse:
    """
    Create a redirect response with a message to show after redirect.

    The message is passed via session to be displayed on the target page.

    Args:
        url: URL to redirect to
        message: Message to display after redirect
        toast_type: Toast type (success, info, warning, error)

    Returns:
        HttpResponse with HX-Redirect header

    Examples:
        return htmx_redirect_with_message('/parks/', 'Park created successfully!')
    """
    resp = HttpResponse("")
    resp["HX-Redirect"] = url
    # Note: The toast will be shown via Django messages framework
    # The view should add the message to the session before returning
    return resp


def htmx_refresh_section(
    target: str,
    html: str = "",
    message: str | None = None,
) -> HttpResponse:
    """
    Create a response that refreshes a specific section.

    Args:
        target: CSS selector for the target element to refresh
        html: HTML content for the response
        message: Optional success message to show

    Returns:
        HttpResponse with retarget header

    Examples:
        return htmx_refresh_section('#park-list', parks_html, 'List updated')
    """
    resp = HttpResponse(html)
    resp["HX-Retarget"] = target
    resp["HX-Reswap"] = "innerHTML"

    if message:
        toast_data = {"type": "success", "message": message, "duration": 3000}
        resp["HX-Trigger"] = json.dumps({"showToast": toast_data})

    return resp


def htmx_modal_close(
    message: str | None = None,
    refresh_target: str | None = None,
    refresh_url: str | None = None,
) -> HttpResponse:
    """
    Create a response that closes a modal and optionally refreshes content.

    Args:
        message: Optional success message to show
        refresh_target: CSS selector for element to refresh
        refresh_url: URL to fetch for refresh content

    Returns:
        HttpResponse with modal close trigger

    Examples:
        return htmx_modal_close('Item saved!', refresh_target='#items-list')
    """
    resp = HttpResponse("")

    triggers: dict[str, Any] = {"closeModal": True}

    if message:
        triggers["showToast"] = {
            "type": "success",
            "message": message,
            "duration": 5000,
        }

    if refresh_target:
        triggers["refreshSection"] = {
            "target": refresh_target,
            "url": refresh_url,
        }

    resp["HX-Trigger"] = json.dumps(triggers)
    return resp


def htmx_validation_response(
    field_name: str,
    errors: list[str] | None = None,
    success_message: str | None = None,
    request: HttpRequest | None = None,
) -> HttpResponse:
    """
    Create a response for inline field validation.

    Args:
        field_name: Name of the field being validated
        errors: List of error messages (None = valid)
        success_message: Message to show on successful validation
        request: Optional request for rendering templates

    Returns:
        HttpResponse with validation feedback HTML

    Examples:
        # Validation error
        return htmx_validation_response('email', errors=['Invalid email format'])

        # Validation success
        return htmx_validation_response('username', success_message='Username available')
    """
    if errors:
        html = render_to_string(
            "forms/partials/field_error.html",
            {"errors": errors},
            request=request,
        )
    elif success_message:
        html = render_to_string(
            "forms/partials/field_success.html",
            {"message": success_message},
            request=request,
        )
    else:
        html = render_to_string(
            "forms/partials/field_success.html",
            {},
            request=request,
        )

    return HttpResponse(html)


def is_htmx_request(request: HttpRequest) -> bool:
    """
    Check if the request is an HTMX request.

    Args:
        request: Django HttpRequest

    Returns:
        True if the request is from HTMX
    """
    return request.headers.get("HX-Request") == "true"


def get_htmx_target(request: HttpRequest) -> str | None:
    """
    Get the target element ID from an HTMX request.

    Args:
        request: Django HttpRequest

    Returns:
        Target element ID or None
    """
    return request.headers.get("HX-Target")


def get_htmx_trigger(request: HttpRequest) -> str | None:
    """
    Get the trigger element ID from an HTMX request.

    Args:
        request: Django HttpRequest

    Returns:
        Trigger element ID or None
    """
    return request.headers.get("HX-Trigger")
