"""
ForeignKeyLinker Module

This module contains a class, ForeignKeyLinker, designed to generate
a function for linking to a related object's change page in the Django admin interface.
The generated function can be used in a Django ModelAdmin class within the list_display
property to display clickable links to related objects.

Classes:
    - ForeignKeyLinker: Generates link functions for related objects in Django admin.

Attributes:
    - field_name (str): The name of the foreign key field in the model.
    - short_description (str, optional): A short description for the function,
    used as the column header. Defaults to the capitalized field name with
    underscores replaced by spaces.
"""
from django.urls import reverse
from django.utils.html import format_html


class ForeignKeyLinker:
    """
    This class is designed to generate a function for linking to a related object's
    change page in the Django admin interface.

    The function generated by an instance of this class can be used in a Django
    ModelAdmin class within the list_display property.

    Attributes:
        field_name (str): The name of the foreign key field in the model.
        short_description (str, optional): The short description for the function.
            If not provided, it defaults to the capitalized field name with underscores
            replaced by spaces.
    """

    def __init__(self, field_name, short_description=None):
        """
        Initialize ForeignKeyLinker with field_name and an optional short_description.
        """
        self.field_name = field_name
        self.short_description = (
            short_description or field_name.replace("_", " ").capitalize()
        )

    def link_to_fk(self, obj):
        """
        Return an HTML link to the related object's change page in the
        Django admin interface.

        Args:
            obj (Model instance): The instance of the model in which the
            foreign key is defined.

        Returns:
            str: An HTML string representing a link to the related object's change page,
            or None if the related object does not exist.
        """
        # Get the related object
        related_obj = getattr(obj, self.field_name)

        if related_obj is None:
            return None

        # Generate the url to the related object's change page
        url = reverse(
            f"admin:{related_obj._meta.app_label}_{related_obj._meta.model_name}_change",
            args=[related_obj.pk],
        )

        # Return the HTML string
        return format_html('<a href="{}">{}</a>', url, related_obj)

    def get_link(self):
        """
        Return the function for use in a Django ModelAdmin class.

        Returns:
            Function: The function to be used in a Django ModelAdmin class.
        """

        # Define the function
        def func(obj):
            return self.link_to_fk(obj)

        func.__name__ = self.field_name
        func.short_description = self.short_description
        func.admin_order_field = self.field_name

        # Return the function
        return func
