def create_segment_priorities_changed_audit_log(  # type: ignore[no-untyped-def]
    previous_id_priority_pairs: typing.List[typing.Tuple[int, int]],
    feature_segment_ids: typing.List[int],
    user_id: int = None,  # type: ignore[assignment]
    master_api_key_id: int = None,  # type: ignore[assignment]
    changed_at: str = None,  # type: ignore[assignment]
):
    """
    This needs to be a separate task called by the view itself. This is because the OrderedModelBase class
    that the FeatureSegment model inherits from implicitly uses bulk update to move other feature segments
    out of the way.

    Given the implementation, it's not really possible (or perhaps desirable) to determine which moves
    were actually made by the user. The logic is such that it iterates over the list of priorities sent
    by the client. Take for example 2 overrides:

     segment_a - priority 0
     segment_b - priority 1

    A change to move segment_b to priority 0 will set the priority on segment_b to 0 (triggering a single
    write to the database). segment_a will be moved from 0 -> 1 using bulk update. This seems fine as we
    then know b was moved and don't really care that a was moved out of the way. If the user, however moves
    segment_a to priority 1, the single save will be done on segment_b since it'll be first in the list and
    segment_a will be bulk updated.

    This is a very simple case, and it likely gets more complicated / difficult to follow if there are more
    than 2 overrides.
    """

    # TODO: use previous priorities to show what changed.

    from features.models import FeatureSegment

    feature_segments = FeatureSegment.objects.filter(id__in=feature_segment_ids)
    if not feature_segments:
        return

    # all feature segments should have the same value for feature, environment and
    # environment feature version
    environment = feature_segments[0].environment
    feature = feature_segments[0].feature
    environment_feature_version_id = feature_segments[0].environment_feature_version_id

    if environment_feature_version_id is not None:
        # Don't create audit logs for FeatureSegments wrapped in a version
        # as this is handled by the feature history instead.
        return

    AuditLog.objects.create(
        log=f"Segment overrides re-ordered for feature '{feature.name}'.",
        environment=environment,
        project_id=environment.project_id,
        author_id=user_id,
        related_object_id=feature.id,
        related_object_type=RelatedObjectType.FEATURE.name,
        master_api_key_id=master_api_key_id,
        created_date=(
            datetime.fromisoformat(changed_at)
            if changed_at is not None
            else timezone.now()
        ),
    )

    This needs to be a separate task called by the view itself. This is because the OrderedModelBase class
    that the FeatureSegment model inherits from implicitly uses bulk update to move other feature segments
    out of the way.

    Given the implementation, it's not really possible (or perhaps desirable) to determine which moves
    were actually made by the user. The logic is such that it iterates over the list of priorities sent
    by the client. Take for example 2 overrides:

     segment_a - priority 0
     segment_b - priority 1

    A change to move segment_b to priority 0 will set the priority on segment_b to 0 (triggering a single
    write to the database). segment_a will be moved from 0 -> 1 using bulk update. This seems fine as we
    then know b was moved and don't really care that a was moved out of the way. If the user, however moves
    segment_a to priority 1, the single save will be done on segment_b since it'll be first in the list and
    segment_a will be bulk updated.

    This is a very simple case, and it likely gets more complicated / difficult to follow if there are more
    than 2 overrides.
    
api/audit/tasks.py