unit Myc.Fmx.AstEditor.Handlers.Pipes;

interface

uses
    System.SysUtils,
    System.UITypes,
    System.Types,
    Myc.Ast,
    Myc.Ast.Nodes,
    Myc.Fmx.AstEditor.Render,
    Myc.Fmx.AstEditor.Node,
    Myc.Fmx.AstEditor.Handlers;

type
    // --- Pipe Container ---

    TPipeNodeHandler = class(TBaseNodeHandler<IPipeNode>)
    private
        FInputsNode: TAstViewNode;
        FTransformNode: TAstViewNode;
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    // --- Pipe Inputs ---

    TPipeInputListHandler = class(TNodeListHandler<IPipeInputNode>)
    protected
        function GetOrientation: TLayoutOrientation; override;
        function GetAlignment: TLayoutAlignment; override;
    public
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    TPipeInputNodeHandler = class(TBaseNodeHandler<IPipeInputNode>)
    private
        FStreamNode: TAstViewNode;
        FSelectorsNode: TAstViewNode;
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    // --- Selectors ---

    TPipeSelectorListHandler = class(TNodeListHandler<IKeywordNode>)
    protected
        function GetOrientation: TLayoutOrientation; override;
    public
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

implementation

{ TPipeNodeHandler }

procedure TPipeNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var
    visu: IAstVisualizer;
    header: TTextNode;
    arrow: TTextNode;
begin
    visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);

    OwnerNode.Frameless := False;
    OwnerNode.Orientation := loVertical;
    OwnerNode.Alignment := laCenter;

    // Distinct background color for Pipes to make them stand out as data flows
    OwnerNode.BackgroundColor := $FF202530;
    OwnerNode.BorderColor := TAlphaColors.Slateblue;

    // Header
    header := OwnerNode.AddLabel(OwnerNode, 'Pipe Pipeline');
    header.FontSettings.Font.Style := [TFontStyle.fsBold];
    header.Color := TAlphaColors.Lightskyblue;

    // Section 1: Inputs
    FInputsNode := visu.CallAccept(FNode.Inputs);

    // Visual Separator / Direction indicator
    arrow := OwnerNode.AddLabel(OwnerNode, '▼ Transform ▼');
    arrow.FontSettings.Font.Size := 10;
    arrow.Color := TAlphaColors.Gray;
    arrow.Margins := TMarginRect.Create(0, 5, 0, 5);

    // Section 2: Transformation (Lambda)
    FTransformNode := visu.CallAccept(FNode.Transformation);
end;

function TPipeNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
    Result :=
        TAst.Pipe(FNode.Identity, FInputsNode.CreateAst.AsPipeInputList, FTransformNode.CreateAst.AsLambdaExpression, FNode.StaticType);
end;

{ TPipeInputListHandler }

function TPipeInputListHandler.GetOrientation: TLayoutOrientation;
begin
    // Stack inputs vertically
    Result := loVertical;
end;

function TPipeInputListHandler.GetAlignment: TLayoutAlignment;
begin
    Result := laFlush;
end;

function TPipeInputListHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
    arr: TArray<IPipeInputNode>;
    i: Integer;
begin
    SetLength(arr, FChildNodes.Count);
    for i := 0 to FChildNodes.Count - 1 do
        arr[i] := FChildNodes[i].CreateAst.AsPipeInput;

    Result := TPipeInputList.Create(arr, FNode.Identity);
end;

{ TPipeInputNodeHandler }

procedure TPipeInputNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var
    visu: IAstVisualizer;
begin
    visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth);

    OwnerNode.Frameless := True;
    OwnerNode.Orientation := loHorizontal;
    OwnerNode.Alignment := laCenter;

    // "StreamName [ :Col :Col ]"
    FStreamNode := visu.CallAccept(FNode.StreamSource);

    // Add small spacing
    var spacer := TAutoFitLayout.Create(OwnerNode.Host);
    spacer.Size := TSizeF.Create(5, 5);
    OwnerNode.AddChild(spacer);

    FSelectorsNode := visu.CallAccept(FNode.Selectors);
end;

function TPipeInputNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
    Result :=
        TAst.PipeInput(
            FNode.StreamSource, // Identifiers are immutable usually, or re-create if needed
            FSelectorsNode.CreateAst.AsPipeSelectorList,
            FNode.Identity.Location
        );
end;

{ TPipeSelectorListHandler }

function TPipeSelectorListHandler.GetOrientation: TLayoutOrientation;
begin
    // Selectors are horizontal: [:A :B :C]
    Result := loHorizontal;
end;

function TPipeSelectorListHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
    arr: TArray<IKeywordNode>;
    i: Integer;
begin
    SetLength(arr, FChildNodes.Count);
    for i := 0 to FChildNodes.Count - 1 do
        arr[i] := FChildNodes[i].CreateAst.AsKeyword;

    Result := TPipeSelectorList.Create(arr, FNode.Identity);
end;

end.
