Editor/PullPreviewWindow.cs
#nullable disable
using System;
using System.Diagnostics;
using System.IO;
using Sandbox;
using Editor;

public class PullPreviewWindow : DockWindow
{
	private readonly string _name;
	private readonly string _localText;
	private readonly string _remoteText;
	private readonly string _warning;
	private readonly Action _apply;
	private Vector2 _mousePos;
	private Rect _applyRect;
	private Rect _cancelRect;
	private Rect _copyRect;
	private float _scroll;

	public PullPreviewWindow( string name, string localText, string remoteText, string warning, Action apply )
	{
		_name = name;
		_localText = localText ?? "";
		_remoteText = remoteText ?? "";
		_warning = warning ?? "";
		_apply = apply;
		Title = $"Pull Preview - {name}";
		Size = new Vector2( 820, 620 );
		MinimumSize = new Vector2( 620, 380 );
		MouseTracking = true;
	}

	protected override void OnPaint()
	{
		base.OnPaint();
		var pad = 14f;
		var y = 16f;
		var w = Width - pad * 2;
		var half = (w - 8) / 2;

		Paint.SetDefaultFont( size: 13, weight: 800 );
		Paint.SetPen( Color.Cyan.WithAlpha( 0.95f ) );
		Paint.DrawText( new Rect( pad, y, w, 22 ), $"Pull remote YAML: {_name}", TextFlag.LeftCenter );
		y += 26;
		Paint.SetDefaultFont( size: 9 );
		Paint.SetPen( string.IsNullOrWhiteSpace( _warning ) ? Color.White.WithAlpha( 0.58f ) : Color.Yellow.WithAlpha( 0.9f ) );
		Paint.DrawText( new Rect( pad, y, w, 16 ), string.IsNullOrWhiteSpace( _warning ) ? "Review the diff before applying remote to local." : _warning, TextFlag.LeftCenter );
		y += 24;

		Paint.SetDefaultFont( size: 9, weight: 700 );
		Paint.SetPen( Color.White.WithAlpha( 0.55f ) );
		Paint.DrawText( new Rect( pad, y, half, 16 ), "LOCAL", TextFlag.LeftCenter );
		Paint.DrawText( new Rect( pad + half + 8, y, half, 16 ), "REMOTE", TextFlag.LeftCenter );
		y += 18;

		var linesL = _localText.Replace( "\r\n", "\n" ).Split( '\n' );
		var linesR = _remoteText.Replace( "\r\n", "\n" ).Split( '\n' );
		var max = Math.Max( linesL.Length, linesR.Length );
		var clipTop = y;
		var footerTop = Math.Max( clipTop + 48f, Height - 96f );
		var clipH = Math.Max( 32f, footerTop - clipTop - 10f );
		var start = Math.Max( 0, (int)(_scroll / 15) );
		var visible = Math.Max( 1, (int)(clipH / 15) );
		Paint.SetDefaultFont( size: 8 );
		for ( var i = start; i < max && i < start + visible; i++ )
		{
			var ly = clipTop + (i - start) * 15;
			var l = i < linesL.Length ? linesL[i] : "";
			var r = i < linesR.Length ? linesR[i] : "";
			var changed = l != r;
			if ( changed )
			{
				Paint.SetBrush( Color.Yellow.WithAlpha( 0.05f ) );
				Paint.SetPen( Color.Transparent );
				Paint.DrawRect( new Rect( pad, ly, w, 15 ) );
			}
			Paint.SetPen( changed ? Color.Yellow.WithAlpha( 0.75f ) : Color.White.WithAlpha( 0.55f ) );
			Paint.DrawText( new Rect( pad, ly, half - 4, 14 ), l, TextFlag.LeftCenter );
			Paint.DrawText( new Rect( pad + half + 8, ly, half - 4, 14 ), r, TextFlag.LeftCenter );
		}

		Paint.SetBrush( Color.Black.WithAlpha( 0.18f ) );
		Paint.SetPen( Color.White.WithAlpha( 0.08f ) );
		Paint.DrawRect( new Rect( 0, footerTop, Width, Height - footerTop ) );

		var btnY = footerTop + 18f;
		_cancelRect = new Rect( pad, btnY, 100, 30 );
		_copyRect = new Rect( pad + 112, btnY, 130, 30 );
		_applyRect = new Rect( Width - pad - 165, btnY, 165, 30 );
		DrawButton( _cancelRect, "Cancel", Color.White );
		DrawButton( _copyRect, "Copy remote YAML", Color.Cyan );
		DrawButton( _applyRect, "Apply remote to local", Color.Green );
	}

	private void DrawButton( Rect rect, string label, Color color )
	{
		var hover = rect.IsInside( _mousePos );
		Paint.SetBrush( color.WithAlpha( hover ? 0.16f : 0.07f ) );
		Paint.SetPen( color.WithAlpha( hover ? 0.5f : 0.24f ) );
		Paint.DrawRect( rect, 4 );
		Paint.SetDefaultFont( size: 9, weight: 800 );
		Paint.SetPen( color.WithAlpha( hover ? 1 : 0.78f ) );
		Paint.DrawText( rect, label, TextFlag.Center );
	}

	protected override void OnMousePress( MouseEvent e )
	{
		if ( _cancelRect.IsInside( e.LocalPosition ) ) Close();
		else if ( _copyRect.IsInside( e.LocalPosition ) ) TryCopy( _remoteText );
		else if ( _applyRect.IsInside( e.LocalPosition ) ) { _apply?.Invoke(); Close(); }
	}

	private static void TryCopy( string text )
	{
		try
		{
			var psi = new ProcessStartInfo { FileName = "powershell.exe", Arguments = "-NoProfile -Command Set-Clipboard", RedirectStandardInput = true, UseShellExecute = false, CreateNoWindow = true };
			using var p = Process.Start( psi );
			p.StandardInput.Write( text ?? "" );
			p.StandardInput.Close();
		}
		catch
		{
			var path = Path.Combine( Path.GetTempPath(), "network-storage-remote.yml" );
			File.WriteAllText( path, text ?? "" );
			EditorUtility.OpenFile( path );
		}
	}

	protected override void OnMouseMove( MouseEvent e ) { _mousePos = e.LocalPosition; Update(); }
	protected override void OnMouseWheel( WheelEvent e ) { _scroll = Math.Max( 0, _scroll + (e.Delta > 0 ? -45 : 45) ); Update(); e.Accept(); }
}