import * as M from '../meta';
import { block, braces, Item, keyvalue, parens, seq } from "./block";
import { FieldType, SimpleType, Type } from "./type";
import { renderType } from "./rendertype";
import { ModuleContext } from './context';

export function genConstructor(
    mod: ModuleContext,
    definitionName: string,
    name: string,
    variant: string | undefined,
    arg: SimpleType,
    resultType: Type,
    resultTypeItem: Item,
): Item[] {
    const formals: Array<[string, FieldType]> = [];
    let simpleValue = false;

    function examine(t: FieldType, name: string): void {
        if (t.kind !== 'unit') {
            formals.push([name, t]);
        }
    }

    if (arg.kind === 'record') {
        arg.fields.forEach(examine);
    } else {
        examine(arg, 'value');
        simpleValue = (variant === void 0) && (arg.kind !== 'unit');
    }

    const initializers: Item[] = (variant !== void 0)
        ? [keyvalue('_variant', JSON.stringify(variant))]
        : [];
    formals.forEach(([n, _t]) => initializers.push(seq(JSON.stringify(n), ': ', M.jsId(n))));

    initializers.push(seq(`__as_preserve__() `, block(`return from${M.jsId(definitionName)}(this)`)));

    const declArgs: Array<Item> = (formals.length > 1)
        ? [seq(braces(...formals.map(f => M.jsId(f[0]))), ': ',
               braces(...formals.map(f => seq(M.jsId(f[0]), ': ', renderType(mod, f[1])))))]
        : formals.map(f => seq(M.jsId(f[0]), ': ', renderType(mod, f[1])));

    return [
        seq(`export function ${M.jsId(name)}`, mod.genericParametersFor(resultType),
            parens(...declArgs),
            ': ', resultTypeItem, ' ', block(
                seq(`return `,
                    (simpleValue
                        ? 'value'
                        : braces(...initializers))))),
        seq(`${M.jsId(name)}.schema = function () `, block(
            seq(`return `, braces(
                `schema: _schema()`,
                `imports: _imports`,
                `definitionName: _.Symbol.for(${JSON.stringify(definitionName)})`,
                ... (variant === void 0) ? [] : [`variant: _.Symbol.for(${JSON.stringify(variant)})`],
            )))),
    ];
}
