import { extractNodeTypeInfo, propagateTypeToAssignOnUse, createNodeData, getOrCreateNode } from './ir_dag.js';
import { recordInBasicBlock } from './ir_cfg.js';
import { BaseType, OpCode, NodeType } from './ir_types.js';
import { c as createStrandsNode } from '../ir_builders-C8mrXj5z.js';
import { userError } from './strands_FES.js';
import './strands_builtins.js';

function buildTernary(strandsContext, condition, ifTrue, ifFalse) {
  const { dag, cfg, p5 } = strandsContext;

  // Ensure all inputs are StrandsNodes
  const condNode = condition?.isStrandsNode ? condition : p5.strandsNode(condition);
  const trueNode = ifTrue?.isStrandsNode ? ifTrue : p5.strandsNode(ifTrue);
  const falseNode = ifFalse?.isStrandsNode ? ifFalse : p5.strandsNode(ifFalse);

  // Get type info for both nodes
  let trueType = extractNodeTypeInfo(dag, trueNode.id);
  let falseType = extractNodeTypeInfo(dag, falseNode.id);

  // Propagate type from the known branch to any ASSIGN_ON_USE branch
  if (trueType.baseType === BaseType.ASSIGN_ON_USE && falseType.baseType !== BaseType.ASSIGN_ON_USE) {
    propagateTypeToAssignOnUse(dag, trueNode.id, falseType.baseType, falseType.dimension);
    trueType = extractNodeTypeInfo(dag, trueNode.id);
  } else if (falseType.baseType === BaseType.ASSIGN_ON_USE && trueType.baseType !== BaseType.ASSIGN_ON_USE) {
    propagateTypeToAssignOnUse(dag, falseNode.id, trueType.baseType, trueType.dimension);
    falseType = extractNodeTypeInfo(dag, falseNode.id);
  }

  // After ASSIGN_ON_USE propagation, if both types are known, they must match
  if (
    trueType.baseType !== BaseType.ASSIGN_ON_USE &&
    falseType.baseType !== BaseType.ASSIGN_ON_USE &&
    (trueType.baseType !== falseType.baseType || trueType.dimension !== falseType.dimension)
  ) {
    userError('type error',
      'The true and false branches of a ternary expression must have the same type. ' +
      `Right now, the true branch is a ${trueType.baseType}${trueType.dimension}, and the false branch is a ${falseType.baseType}${falseType.dimension}.`
    );
  }

  const resultType = trueType;

  const nodeData = createNodeData({
    nodeType: NodeType.OPERATION,
    opCode: OpCode.Nary.TERNARY,
    dependsOn: [condNode.id, trueNode.id, falseNode.id],
    baseType: resultType.baseType,
    dimension: resultType.dimension,
  });

  const id = getOrCreateNode(dag, nodeData);
  recordInBasicBlock(cfg, cfg.currentBlock, id);
  return createStrandsNode(id, resultType.dimension, strandsContext);
}

export { buildTernary };
