import { upperFirst } from 'lodash-es';
import { Validations } from '../built-in-options/index.js';
import { relationshipTypeExists } from '../basic-types/relationship-types.js';
const { REQUIRED } = Validations;
export default class JDLRelationship {
    side;
    from;
    to;
    type;
    options;
    injectedFieldInFrom;
    injectedFieldInTo;
    isInjectedFieldInFromRequired;
    isInjectedFieldInToRequired;
    commentInFrom;
    commentInTo;
    constructor(args) {
        const merged = mergeDefaultsWithOverrides(args);
        if (!merged.from || !merged.to) {
            throw new Error('Source and destination entities must be passed to create a relationship.');
        }
        if (!relationshipTypeExists(merged.type) || !(merged.injectedFieldInFrom || merged.injectedFieldInTo)) {
            throw new Error('A valid type and at least one injected field must be passed to create a relationship.');
        }
        this.side = merged.side;
        this.from = merged.from;
        this.to = merged.to;
        this.type = merged.type;
        this.options = merged.options;
        this.injectedFieldInFrom = merged.injectedFieldInFrom;
        this.injectedFieldInTo = merged.injectedFieldInTo;
        this.isInjectedFieldInFromRequired = merged.isInjectedFieldInFromRequired;
        this.isInjectedFieldInToRequired = merged.isInjectedFieldInToRequired;
        this.commentInFrom = merged.commentInFrom;
        this.commentInTo = merged.commentInTo;
    }
    getId() {
        return (`${this.type}_${this.from}${this.injectedFieldInFrom ? `{${this.injectedFieldInFrom}}` : ''}` +
            `_${this.to}${this.injectedFieldInTo ? `{${this.injectedFieldInTo}}` : ''}`);
    }
    hasGlobalOption(option) {
        return option in this.options.global;
    }
    forEachGlobalOption(passedFunction) {
        Object.entries(this.options.global).forEach(([key, value]) => {
            passedFunction(key, value);
        });
    }
    forEachSourceOption(passedFunction) {
        Object.entries(this.options.source).forEach(([key, value]) => {
            passedFunction(key, value);
        });
    }
    forEachDestinationOption(passedFunction) {
        Object.entries(this.options.destination).forEach(([key, value]) => {
            passedFunction(key, value);
        });
    }
    toString() {
        let string = `relationship ${this.type} {\n  `;
        if (this.commentInFrom) {
            string += `/**\n${this.commentInFrom
                .split('\n')
                .map(line => `   * ${line}\n`)
                .join('')}   */\n  `;
        }
        const sourceOptions = this.options.source;
        if (Object.keys(sourceOptions).length !== 0) {
            Object.keys(sourceOptions).forEach(name => {
                const value = sourceOptions[name];
                name = upperFirst(name);
                string += `@${name}${value != null && value !== true ? `(${value}) ` : ' '}`;
            });
        }
        string += `${this.from}`;
        if (this.injectedFieldInFrom) {
            string += `{${this.injectedFieldInFrom}${this.isInjectedFieldInFromRequired ? ` ${REQUIRED}` : ''}}`;
        }
        string += ' to';
        if (this.commentInTo) {
            string += `\n  /**\n${this.commentInTo
                .split('\n')
                .map(line => `   * ${line}\n`)
                .join('')}   */\n  `;
        }
        else {
            string += ' ';
        }
        const destinationOptions = this.options.destination;
        if (Object.keys(destinationOptions).length !== 0) {
            Object.keys(destinationOptions).forEach(name => {
                const value = destinationOptions[name];
                name = upperFirst(name);
                string += `@${name}${value != null && value !== true ? `(${value}) ` : ' '}`;
            });
        }
        string += `${this.to}`;
        if (this.injectedFieldInTo) {
            string += `{${this.injectedFieldInTo}${this.isInjectedFieldInToRequired ? ` ${REQUIRED}` : ''}}`;
        }
        const globalOptions = this.options.global;
        if (Object.keys(globalOptions).length !== 0) {
            string += ' with ';
            Object.keys(globalOptions).forEach(name => {
                string += `${name}, `;
            });
            string = string.substring(0, string.length - 2);
        }
        string += '\n}';
        return string.replace(/ \n/g, '\n').replace(/[ ]{4}/g, '  ');
    }
}
function mergeDefaultsWithOverrides(overrides) {
    const defaultOptions = defaults();
    const mergedOptions = {
        ...defaultOptions,
        ...overrides,
    };
    mergedOptions.options.global = mergedOptions.options.global || {};
    mergedOptions.options.source = mergedOptions.options.source || {};
    mergedOptions.options.destination = mergedOptions.options.destination || {};
    return mergedOptions;
}
function defaults() {
    return {
        side: undefined,
        injectedFieldInFrom: null,
        injectedFieldInTo: null,
        isInjectedFieldInFromRequired: false,
        isInjectedFieldInToRequired: false,
        options: {
            global: {},
            destination: {},
            source: {},
        },
        commentInFrom: '',
        commentInTo: '',
    };
}
