package estransforms

import (
	"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
	"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
)

type logicalAssignmentTransformer struct {
	transformers.Transformer
}

func (ch *logicalAssignmentTransformer) visit(node *ast.Node) *ast.Node {
	if node.SubtreeFacts()&ast.SubtreeContainsLogicalAssignments == 0 {
		return node
	}
	switch node.Kind {
	case ast.KindBinaryExpression:
		return ch.visitBinaryExpression(node.AsBinaryExpression())
	default:
		return ch.Visitor().VisitEachChild(node)
	}
}

func (ch *logicalAssignmentTransformer) visitBinaryExpression(node *ast.BinaryExpression) *ast.Node {
	var nonAssignmentOperator ast.Kind
	switch node.OperatorToken.Kind {
	case ast.KindBarBarEqualsToken:
		nonAssignmentOperator = ast.KindBarBarToken
	case ast.KindAmpersandAmpersandEqualsToken:
		nonAssignmentOperator = ast.KindAmpersandAmpersandToken
	case ast.KindQuestionQuestionEqualsToken:
		nonAssignmentOperator = ast.KindQuestionQuestionToken
	default:
		return ch.Visitor().VisitEachChild(node.AsNode())
	}

	left := ast.SkipParentheses(ch.Visitor().VisitNode(node.Left))
	assignmentTarget := left
	right := ast.SkipParentheses(ch.Visitor().VisitNode(node.Right))

	if ast.IsAccessExpression(left) {
		propertyAccessTargetSimpleCopiable := transformers.IsSimpleCopiableExpression(left.Expression())
		propertyAccessTarget := left.Expression()
		propertyAccessTargetAssignment := left.Expression()
		if !propertyAccessTargetSimpleCopiable {
			propertyAccessTarget = ch.Factory().NewTempVariable()
			ch.EmitContext().AddVariableDeclaration(propertyAccessTarget)
			propertyAccessTargetAssignment = ch.Factory().NewAssignmentExpression(
				propertyAccessTarget,
				left.Expression(),
			)
		}

		if ast.IsPropertyAccessExpression(left) {
			assignmentTarget = ch.Factory().NewPropertyAccessExpression(
				propertyAccessTarget,
				nil,
				left.Name(),
				ast.NodeFlagsNone,
			)
			left = ch.Factory().NewPropertyAccessExpression(
				propertyAccessTargetAssignment,
				nil,
				left.Name(),
				ast.NodeFlagsNone,
			)
		} else {
			elementAccessArgumentSimpleCopiable := transformers.IsSimpleCopiableExpression(left.AsElementAccessExpression().ArgumentExpression)
			elementAccessArgument := left.AsElementAccessExpression().ArgumentExpression
			argumentExpr := elementAccessArgument
			if !elementAccessArgumentSimpleCopiable {
				elementAccessArgument = ch.Factory().NewTempVariable()
				ch.EmitContext().AddVariableDeclaration(elementAccessArgument)
				argumentExpr = ch.Factory().NewAssignmentExpression(
					elementAccessArgument,
					left.AsElementAccessExpression().ArgumentExpression,
				)
			}

			assignmentTarget = ch.Factory().NewElementAccessExpression(
				propertyAccessTarget,
				nil,
				elementAccessArgument,
				ast.NodeFlagsNone,
			)
			left = ch.Factory().NewElementAccessExpression(
				propertyAccessTargetAssignment,
				nil,
				argumentExpr,
				ast.NodeFlagsNone,
			)
		}

	}

	return ch.Factory().NewBinaryExpression(
		nil,
		left,
		nil,
		ch.Factory().NewToken(nonAssignmentOperator),
		ch.Factory().NewParenthesizedExpression(
			ch.Factory().NewAssignmentExpression(
				assignmentTarget,
				right,
			),
		),
	)
}

func newLogicalAssignmentTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
	tx := &logicalAssignmentTransformer{}
	return tx.NewTransformer(tx.visit, opts.Context)
}
