#!/usr/bin/env node

'use strict';

const dateTimeGenerator = require('../utility/dateTimeGenerator');
const LexiconService = require('../../../VDM/prototypes/lexiconService');

const RPC_EMULATOR_MODEL = [
    {
        id: 'ORQQPL4_LEX',
        name: 'ORQQPL4 LEX',
        function: 'LEX^ORQQPL4',
        domain: 'UTILITY',
        parameters: [],
        files: [],
        mvdm: {},
        labels: ['LEXICON', 'META'],
        rpcType: 'READ',
        complexity: 'DIFFICULT',
        description: 'This RPC supports the Clinical Lexicon Search for Problem List. It will return an indefinite list of terms that match the user\'s search string.',
        returnType: 'GLOBAL ARRAY',
        inputParameters: [{
            id: 'X',
            parameterType: 'LITERAL',
            required: true,
            description: 'The search text entered by the user',
            example: 'HYPERTENSION',
        }, {
            id: 'VIEW',
            parameterType: 'LITERAL',
            required: false,
            description: 'The Lexicon VIEW parameter',
            example: 'PLS',
        }, {
            id: 'ORDATE',
            parameterType: 'LITERAL',
            required: false,
            description: 'the date of interest in FM format (defaults to TODAY)',
            example: '3161011.152823',
        }, {
            id: 'ORINCSYN',
            parameterType: 'LITERAL',
            required: false,
            description: 'Boolean flag specifying whether or not to include synonyms for SNOMED CT Concepts'
                            + '(defaults to 0 (false))',
            example: '1',
        }],

        processRPCInvocation(rpcArgs) {
            // GETDX^ORQQPL1
            function getDx(code, sys, oridt) {
                const _oridt = oridt || dateTimeGenerator('TODAY').split('.')[0];
                let ory = 0;
                const implDT = LexiconService.getImplementationDate('10D');
                const oruh = (_oridt < implDT) ? '799.9' : 'R69.';
                if (sys && sys.includes('VHAT')) {
                    ory = (_oridt < implDT) ? LexiconService.getAssociations(code, 'VHAT2ICD').codes : 0;
                } else {
                    ory = (_oridt < implDT) ? LexiconService.getAssociations(code, 'SCT2ICD').codes : 0;
                }
                if (!ory || isNaN(parseInt(ory, 10))) {
                    return oruh;
                }
                return '.';
            }

            // SETELEM^ORQQPL4
            function setElem(orlex, ortxt, orcodsys, orccode, ordate, ordcode) {
                const orimpdt = LexiconService.getImplementationDate('10D');
                let _ordcode = ordcode;
                let matchFound = false;
                if (!_ordcode) {
                    _ordcode = LexiconService.getSynonyms(orccode, 'SCT', { includeIEN: 1, designationIds: 1 });
                    if (_ordcode.status !== 1) _ordcode = '';
                    // search thru synonyms, preferred, and full props for ortxt
                    else if (_ordcode.synonyms.some((synonym, i) => {
                        if (synonym.split('^')[0] === ortxt) {
                            _ordcode = synonym.split('^')[2];
                            matchFound = true;
                            return true;
                        }
                        return false;
                    }));
                    else if (_ordcode.preferred.split('^')[0] === ortxt) {
                        _ordcode = _ordcode.preferred.split('^')[2];
                        matchFound = true;
                    } else if (_ordcode.full.split('^')[0] === ortxt) {
                        _ordcode = _ordcode.full.split('^')[2];
                        matchFound = true;
                    }
                }
                const oricd = getDx(orccode, orcodsys, ordate);
                const oricdid = parseInt(LexiconService.getICDData(oricd.split('/')[0], 'DIAG', { date: ordate }), 10);
                if (!matchFound && !_ordcode) _ordcode = '';
                let ory = `${orlex}^${ortxt}^${oricd}^${oricdid}^${orcodsys}^${orccode}^${_ordcode}`;
                if (orcodsys && (orcodsys.includes('SNOMED') || orcodsys.includes('VHAT'))) {
                    ory = `${ory}^${ordate < orimpdt ? 'ICD-9-CM' : 'ICD-10-CM'}`;
                }
                return ory;
            }

            // LEXXFRM^ORQQPL4
            function lexxfrm(orx, ordate, orapp) {
                const orlex = orx.id;
                let ortxt = orx.value || '';
                let orccode = '';
                let orcodsys = 0;
                ortxt.replace(/\*/g, '');
                if (ortxt.includes('(') && ortxt.includes(')')) {
                    orcodsys = ortxt.substring(ortxt.lastIndexOf('(') + 1, ortxt.lastIndexOf(')'));
                    orccode = LexiconService.getCode(parseInt(orlex, 10), 'SCT', { date: ordate });
                    orcodsys = orcodsys.substring(0, orcodsys.lastIndexOf(' '));
                    ortxt = ortxt.substring(0, ortxt.lastIndexOf('(')).trim();
                }
                const ory = setElem(orlex, ortxt, orcodsys, orccode, ordate);
                return ory;
            }

            // SYNONYMS^ORQQPL4
            function synonyms(lst, orcsys, orccode, ordt) {
                const ordad = lst.length;
                const orsyn = LexiconService.getSynonyms(orccode, orcsys,
                                { includeIEN: 1, designationIds: 1, date: ordt });
                if (orsyn.status !== 1) return lst;
                orsyn.synonyms.forEach((synonym) => {
                    const synonymArr = synonym.split('^');
                    const ien = synonymArr[1] || '';
                    const txt = synonymArr[0];
                    const ordcode = synonymArr[2] || '';
                    const element = `${setElem(ien, txt, 'SNOMED CT', orccode, ordt, ordcode)}^${ordad}`;
                    lst.push(element);
                });
                return lst;
            }

            // LEX^ORQQPL4
            let res = [];
            const x = rpcArgs[0].toString();
            const view = rpcArgs[1] || 'PLS';
            let ordate = rpcArgs[2] || '';
            const orincsyn = rpcArgs[3] || 0;
            const app = 'GMPX';
            if (!ordate || isNaN(parseInt(ordate, 10))) ordate = parseInt(dateTimeGenerator('TODAY').toString().split('.')[0], 10);
            if (x.match(/^[A-z]?\d{2,3}\.?\d{0,2}/) || x.match(/^[A-z]?\d{2,3}\+/)) {
                res.push('icd^Searching by code on the Problems Tab supports SNOMED CT, but not ICD.');
                res.push('Please try a different search');
                return res;
            }
            const lookup = LexiconService.lookup(x, app, { length: 5, date: ordate, subset: view });
            if (!lookup.list || lookup.list.length === 0) return ['Code search failed'];
            lookup.list.forEach((val) => {
                const element = lexxfrm(val, ordate, app);
                res.push(element);
                if (orincsyn) res = synonyms(res, 'SCT', element.split('^')[5], ordate);
            });
            const lookupAllList = LexiconService.lookup(x, app, { date: ordate, subset: view, allEntries: true });
            lookupAllList.list.forEach((val) => {
                const element = lexxfrm(val, ordate, app);
                res.push(element);
                if (orincsyn) res = synonyms(res, 'SCT', element.split('^')[5], ordate);
            });
            if (!res || res.length < 1) return ['No matches found'];
            res.push(`${res.length}${res.length === 1 ? ' match' : ' matches'} found`);
            return res;
        },
        toReturnValue(res) {
            return res;
        },
    },
];

module.exports.rpcEmulatorModel = RPC_EMULATOR_MODEL;
