/**
 * @module
 * Définit le modèle de données utilisé par l’application.
 */

import PropTypes from 'prop-types';

/**
 * Types de termes existants.
 */
export const termTypes = {
    disease: 'Maladie',
    symptom: 'Symptôme',
    sign: 'Signe',
};

/**
 * Crée un valideur de type de propriété React supportant l’extension
 * `.isRequired` pour marquer une propriété comme requise.
 *
 * @param basicValidator Fonction basique de validation.
 * @return Fonction augmentée supportant l’extension `.isRequired`.
 */
const makePropType = basicValidator =>
{
    const validator = (props, propName, componentName) =>
    {
        // Version optionnelle : on n’appelle le valideur que si la propriété a
        // été passée
        if (propName in props)
        {
            return basicValidator(props, propName, componentName);
        }
    };

    validator.isRequired = (props, propName, componentName) =>
    {
        // Version obligatoire : on jette une erreur si la propriété n’a pas
        // été passée puis on procède à la validation
        if (!(propName in props))
        {
            return new Error(
                `Missing prop “${propName}” in props supplied to `
                + `${componentName}.`
            );
        }

        return basicValidator(props, propName, componentName);
    };

    return validator;
};

/**
 * Type de terme.
 */
export const TermType = PropTypes.oneOf(Object.values(termTypes));

/**
 * URL.
 */
const URL = makePropType((props, propName, componentName) =>
{
    const value = props[propName];

    if (typeof value !== 'string')
    {
        return new Error(
            `URL passed as ${componentName}’s ${propName} prop must be `
            + `a string, not a ${typeof value}.`
        );
    }

    if (!value.startsWith('http://') && !value.startsWith('https://'))
    {
        return new Error(
            `URL “${value}”, passed as ${componentName}’s ${propName} `
            + 'prop, does not start with “http://” or “https://”.'
        );
    }
});

/**
 * Terme.
 *
 * Peut être une maladie, un symptôme ou un signe.
 */
export const Term = PropTypes.exact({
    // Identifiant unique
    id: PropTypes.string.isRequired,

    // Nom canonique
    name: PropTypes.string.isRequired,

    // Noms alternatifs
    alias: PropTypes.arrayOf(PropTypes.string).isRequired,

    // Types (maladie, symptôme, signe)
    types: PropTypes.arrayOf(TermType).isRequired,

    // Facteur d’importance
    weight: PropTypes.number.isRequired,

    // Adresse de la ressource de référence
    url: URL.isRequired,
});

/**
 * Relation entre deux termes.
 */
export const Relation = makePropType((props, propName) =>
{
    const value = props[propName];

    if (!Array.isArray(value))
    {
        return new Error(
            `Relation ${propName} must be an array.`
        );
    }

    if (value.length !== 2)
    {
        return new Error(
            `Relation ${propName} must contain exactly two entries.`
        );
    }
});
