package loader

import (
	"testing"

	"github.com/marzeq/qk/codegen/irgen"
	"github.com/marzeq/qk/ir"
	"github.com/marzeq/qk/types"
)

func TestExtractGenericSpecializationsRenamesFunctionConstantCallee(t *testing.T) {
	parameter := types.TypeParameter{Owner: "example.make", Name: "T", Index: 0}
	baseName := irgen.MangleFunctionName("example", "make")
	signature := ir.FunctionSignature{ReturnType: types.PrimitiveVoid}
	templateFunction := ir.NewFunction(baseName, ir.LinkageInternal, nil)
	templateFunction.Signature = signature
	templateFunction.Entry = templateFunction.NewBlock("entry").ID
	templateFunction.Blocks[0].Instr = append(templateFunction.Blocks[0].Instr, ir.Return{})
	template := ir.GenericTemplate{
		Module: "example", Name: "make", Parameters: []types.TypeParameter{parameter},
		Functions: []*ir.Function{templateFunction},
	}

	caller := ir.NewFunction("caller", ir.LinkageInternal, nil)
	caller.Signature = signature
	caller.Entry = caller.NewBlock("entry").ID
	callee := ir.FunctionConstOperand(baseName, types.PointerType{Base: types.FunctionType{ReturnType: types.PrimitiveVoid}})
	caller.Blocks[0].Instr = append(caller.Blocks[0].Instr,
		ir.Call{Callee: &callee, Signature: signature, Generic: &ir.GenericReference{
			Module: "example", Name: "make", TypeArguments: []types.Type{types.PrimitiveU8},
		}},
		ir.Return{},
	)

	units, err := ExtractGenericSpecializationUnits(
		map[string]*ir.Module{"main": {Functions: []*ir.Function{caller}}},
		map[string][]ir.GenericTemplate{"example": {template}},
		nil,
	)
	if err != nil {
		t.Fatal(err)
	}
	call := caller.Blocks[0].Instr[0].(ir.Call)
	if call.Generic == nil {
		t.Fatal("generic demand metadata was not preserved")
	}
	if call.Callee == nil || call.Callee.FunctionName == baseName {
		t.Fatalf("function-constant callee was not specialized: %#v", call.Callee)
	}
	if len(units) != 1 || units[0].DefiningModule != "example" || units[0].Key == "" {
		t.Fatalf("unexpected specialization units: %#v", units)
	}
	if len(units[0].IR.Functions) != 1 || units[0].IR.Functions[0].Name != call.Callee.FunctionName {
		t.Fatalf("specialization target %q does not match generated function", call.Callee.FunctionName)
	}
}