unit Myc.Fmx.AstEditor.Handlers.Data;

interface

uses
    System.SysUtils,
    System.UITypes,
    Myc.Data.Keyword,
    Myc.Ast,
    Myc.Ast.Nodes,
    Myc.Fmx.AstEditor.Render,
    Myc.Fmx.AstEditor.Node;

type
    // --- Declarations & Assignments ---

    TVariableDeclarationNodeHandler = class(TBaseNodeHandler<IVariableDeclarationNode>)
    private
        FTargetNode: TAstViewNode;
        FInitializerNode: TAstViewNode;
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    TAssignmentNodeHandler = class(TBaseNodeHandler<IAssignmentNode>)
    private
        FTargetNode: TAstViewNode;
        FValueNode: TAstViewNode;
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    // --- Metaprogramming ---

    TQuasiquoteNodeHandler = class(TBaseNodeHandler<IQuasiquoteNode>)
    private
        FExpressionNode: TAstViewNode;
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    TUnquoteNodeHandler = class(TBaseNodeHandler<IUnquoteNode>)
    private
        FExpressionNode: TAstViewNode;
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    TUnquoteSplicingNodeHandler = class(TBaseNodeHandler<IUnquoteSplicingNode>)
    private
        FExpressionNode: TAstViewNode;
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    // --- Data Access & Structures ---

    TIndexerNodeHandler = class(TBaseNodeHandler<IIndexerNode>)
    private
        FBaseNode: TAstViewNode;
        FIndexNode: TAstViewNode;
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    TMemberAccessNodeHandler = class(TBaseNodeHandler<IMemberAccessNode>)
    private
        FBaseNode: TAstViewNode;
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    TRecordFieldHandler = class(TBaseNodeHandler<IRecordFieldNode>)
    private
        FKeyLabel: TTextNode;
        FValueNode: TAstViewNode;
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    TRecordLiteralNodeHandler = class(TBaseNodeHandler<IRecordLiteralNode>)
    private
        FFieldsNode: TAstViewNode;
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    // --- Series Operations ---

    TCreateSeriesNodeHandler = class(TBaseNodeHandler<ICreateSeriesNode>)
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    TAddSeriesItemNodeHandler = class(TBaseNodeHandler<IAddSeriesItemNode>)
    private
        FValueNode: TAstViewNode;
        FLookbackNode: TAstViewNode;
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

    TSeriesLengthNodeHandler = class(TBaseNodeHandler<ISeriesLengthNode>)
    public
        procedure BuildUI(OwnerNode: TAstViewNode); override;
        function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
    end;

implementation

{ TVariableDeclarationNodeHandler }

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

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

    varLabel := OwnerNode.AddLabel(OwnerNode, 'var');

    varLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
    FTargetNode := visu.CallAccept(FNode.Target);

    if Assigned(FNode.Initializer) then
    begin
        OwnerNode.AddLabel(OwnerNode, ':=');
        FInitializerNode := visu.CallAccept(FNode.Initializer);
    end
    else
        FInitializerNode := nil;
end;

function TVariableDeclarationNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
    initAst: IAstNode;
begin
    if Assigned(FInitializerNode) then
        initAst := FInitializerNode.CreateAst
    else
        initAst := nil;
    Result := TAst.VarDecl(FNode.Identity, FTargetNode.CreateAst, initAst, FNode.StaticType, FNode.IsBoxed);
end;

{ TAssignmentNodeHandler }

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

    OwnerNode.Frameless := True;
    OwnerNode.Orientation := loHorizontal;
    FTargetNode := visu.CallAccept(FNode.Target);
    OwnerNode.AddLabel(OwnerNode, ':=');
    FValueNode := visu.CallAccept(FNode.Value);
end;

function TAssignmentNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
    Result := TAst.Assign(FNode.Identity, FTargetNode.CreateAst, FValueNode.CreateAst, FNode.StaticType);
end;

{ TQuasiquoteNodeHandler }

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

    OwnerNode.Frameless := False;
    OwnerNode.Orientation := loVertical;
    titleLabel := OwnerNode.AddLabel(OwnerNode, 'Quasiquote');
    titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
    FExpressionNode := visu.CallAccept(FNode.Expression);
end;

function TQuasiquoteNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
    Result := TAst.Quasiquote(FNode.Identity, FExpressionNode.CreateAst);
end;

{ TUnquoteNodeHandler }

procedure TUnquoteNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var
    visu: IAstVisualizer;
    leftBracket, rightBracket: TTextNode;
begin
    visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);

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

    leftBracket := OwnerNode.AddLabel(OwnerNode, '<');
    // We cannot assign to fields of record properties directly.
    // Replace the entire margin record.
    // Default from AddLabel is (cNodePadding, cTitleTopPadding, cNodePadding, cTitleBottomPadding)
    // We want Right Margin = 0.
    leftBracket.Margins := TMarginRect.Create(cNodePadding, cTitleTopPadding, 0, cTitleBottomPadding);

    FExpressionNode := visu.CallAccept(FNode.Expression);

    rightBracket := OwnerNode.AddLabel(OwnerNode, '>');
    // We want Left Margin = 0.
    rightBracket.Margins := TMarginRect.Create(0, cTitleTopPadding, cNodePadding, cTitleBottomPadding);
end;

function TUnquoteNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
    Result := TAst.Unquote(FNode.Identity, FExpressionNode.CreateAst);
end;

{ TUnquoteSplicingNodeHandler }

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

    OwnerNode.Frameless := False;
    OwnerNode.Orientation := loVertical;
    titleLabel := OwnerNode.AddLabel(OwnerNode, 'Unquote-Splicing');
    titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
    FExpressionNode := visu.CallAccept(FNode.Expression);
end;

function TUnquoteSplicingNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
    Result := TAst.UnquoteSplicing(FNode.Identity, FExpressionNode.CreateAst.AsQuasiquote);
end;

{ TIndexerNodeHandler }

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

    OwnerNode.Frameless := True;
    OwnerNode.Orientation := loHorizontal;
    FBaseNode := visu.CallAccept(FNode.Base);
    OwnerNode.AddLabel(OwnerNode, '[');
    FIndexNode := visu.CallAccept(FNode.Index);
    OwnerNode.AddLabel(OwnerNode, ']');
end;

function TIndexerNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
    Result := TAst.Indexer(FNode.Identity, FBaseNode.CreateAst, FIndexNode.CreateAst, FNode.StaticType);
end;

{ TMemberAccessNodeHandler }

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

    OwnerNode.Frameless := True;
    OwnerNode.Orientation := loHorizontal;
    FBaseNode := visu.CallAccept(FNode.Base);
    OwnerNode.AddLabel(OwnerNode, '.');
    OwnerNode.AddLabel(OwnerNode, FNode.Member.Value.Name);
end;

function TMemberAccessNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
    Result := TAst.MemberAccess(FNode.Identity, FBaseNode.CreateAst, TAst.Keyword(FNode.Member.Identity.AsKeyword), FNode.StaticType);
end;

{ TRecordFieldHandler }

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

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

    FKeyLabel := OwnerNode.AddLabel(OwnerNode, ':' + FNode.Key.Value.Name);
    FKeyLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
    FKeyLabel.Color := TAlphaColors.Mediumvioletred;

    FValueNode := visu.CallAccept(FNode.Value);
end;

function TRecordFieldHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
    Result := TAst.RecordField(FNode.Identity, FNode.Key, FValueNode.CreateAst);
end;

{ TRecordLiteralNodeHandler }

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

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

    // Delegate to RecordFieldList
    FFieldsNode := visu.CallAccept(FNode.Fields);
end;

function TRecordLiteralNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
    Result :=
        TAst.RecordLiteral(
            FNode.Identity,
            FFieldsNode.CreateAst.AsRecordFieldList,
            FNode.ScalarDefinition,
            FNode.GenericDefinition,
            FNode.StaticType
        );
end;

{ TCreateSeriesNodeHandler }

procedure TCreateSeriesNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var
    titleLabel: TTextNode;
begin
    OwnerNode.Frameless := False;
    OwnerNode.Orientation := loVertical;
    titleLabel := OwnerNode.AddLabel(OwnerNode, 'Create Series: ' + FNode.Definition);
    titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
end;

function TCreateSeriesNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
    Result := TAst.CreateSeries(FNode.Identity.AsDefinition, FNode.StaticType);
end;

{ TAddSeriesItemNodeHandler }

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

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

    titleLabel := OwnerNode.AddLabel(OwnerNode, 'Add Item to: ' + FNode.Series.Name);
    titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];

    FValueNode := visu.CallAccept(FNode.Value);
    if Assigned(FNode.Lookback) then
        FLookbackNode := visu.CallAccept(FNode.Lookback)
    else
        FLookbackNode := nil;
end;

function TAddSeriesItemNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
    lookbackAst: IAstNode;
begin
    if Assigned(FLookbackNode) then
        lookbackAst := FLookbackNode.CreateAst
    else
        lookbackAst := nil;

    Result :=
        TAst.AddSeriesItem(
            FNode.Identity,
            FNode.Series, // Reuse original Series Identifier Node
            FValueNode.CreateAst,
            lookbackAst,
            FNode.StaticType
        );
end;

{ TSeriesLengthNodeHandler }

procedure TSeriesLengthNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var
    titleLabel: TTextNode;
begin
    OwnerNode.Frameless := False;
    OwnerNode.Orientation := loVertical;
    titleLabel := OwnerNode.AddLabel(OwnerNode, 'Length of: ' + FNode.Series.Name);
    titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
end;

function TSeriesLengthNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
    Result := TAst.SeriesLength(FNode.Identity, FNode.Series, FNode.StaticType);
end;

end.
