Editor/Walkway/ArchWalkwayConnectionService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;

namespace Sunless.Architecture;


sealed class ArchWalkwayConnectionService {
	readonly ArchConnections connections;
	readonly ArchBuilding preferredHost;
	readonly IReadOnlyList<(Vector2 From, Vector2 To)> mouths;
	readonly float clear;

	public ArchWalkwayConnectionService(
		ArchConnections connections,
		ArchBuilding preferredHost,
		IReadOnlyList<(Vector2 From, Vector2 To)> mouths,
		float clear ) {
		this.connections = connections;
		this.preferredHost = preferredHost;
		this.mouths = mouths;
		this.clear = clear;
	}

	// The geometry already resolved which room each mouth cuts - the far one may be a storey up.
	public IReadOnlyList<ArchWalkwayEndpoint> ResolveEndpoints( ArchWalkwaySpan span ) {
		return span.Mouths
			.Select( ( mouth, index ) => {
				var point = (mouth.From + mouth.To) * 0.5f;
				var room = span.EndRooms[index];

				return new ArchWalkwayEndpoint {
					Point = point,
					Room = room,
					Building = room is null ? preferredHost : FindBuilding( room )
				};
			} )
			.ToList();
	}

	// Resolves WHERE the link lands, and cuts nothing. The mouths are an effect the link owns, so
	// ArchWalkwayConnection re-derives them on every commit - breaching here as well would bake a
	// hole the re-derive could not find again, and the link would drop its own group on the next one.
	public ArchWalkwayConnectionResult Connect( ArchRoom room, IReadOnlyList<ArchWalkwayEndpoint> endpoints ) {
		var opened = endpoints
			.Select( endpoint => endpoint.Room )
			.Where( reached => reached is not null )
			.Distinct()
			.ToList();

		var host = opened.Select( reached => connections.Plan.OwnerOf( reached ) )
			.FirstOrDefault( owner => ReferenceEquals( owner, preferredHost ) )
			?? opened.Select( reached => connections.Plan.OwnerOf( reached ) ).FirstOrDefault( owner => owner is not null )
			?? preferredHost;

		return new ArchWalkwayConnectionResult { Host = host, Opened = opened, Endpoints = endpoints };
	}

	ArchBuilding FindBuilding( ArchRoom room ) => connections.Plan.OwnerOf( room );
}