import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;

using haxe.macro.Tools;

class EitherMacro {
    static var arityMap = new Map<Int,Bool>();

    static function build():ComplexType {
        return switch (Context.getLocalType()) {
            case TInst(_.get() => {pack: [], name: "Either"}, params):
                return buildEitherType(params);
            default:
                throw false;
        }
    }

    static function buildEitherType(types:Array<Type>):ComplexType {
        var pos = Context.currentPos();
        var arity = types.length;
        if (arity < 2)
            Context.fatalError("Either should only be used with 2 or more type parameters", pos);
        var name = 'Either_$arity';
        if (!arityMap.exists(arity)) {
            var fromToTypes:Array<ComplexType> = [];
            var params:Array<TypeParamDecl> = [];
            for (i in 0...arity) {
                var name = 'T$i';
                fromToTypes.push(TPath({pack: [], name: name}));
                params.push({name: name});
            }
            Context.defineType({
                name: name,
                pos: pos,
                pack: [],
                params: params,
                kind: TDAbstract(macro : Dynamic, fromToTypes, fromToTypes),
                fields: []
            });
            arityMap[arity] = true;
        }
        return TPath({pack: [], name: name, params: [for (t in types) TPType(t.toComplexType())]});
    }
}