"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: Object.getOwnPropertyDescriptor(all, name).get
    });
}
_export(exports, {
    get readMetadata () {
        return readMetadata;
    },
    get readTwoModelTypeSheet () {
        return readTwoModelTypeSheet;
    }
});
const _logging = require("@tamanu/shared/services/logging");
const _config = /*#__PURE__*/ _interop_require_default(require("config"));
const _xlsx = require("xlsx");
const _errors = require("../errors");
const _idify = require("./idify");
const _constants = require("@tamanu/constants");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
function checkHomeServer(homeServer) {
    _logging.log.debug('Check where we are importing');
    if (!homeServer) return true;
    // detect if we're importing to home server
    const { canonicalHostName: host } = _config.default;
    // ignore slashes when comparing servers - easiest way to account for trailing slashes that may or may not be present
    const importingToHome = homeServer.replace('/', '') === host.replace('/', '');
    if (!importingToHome) {
        if (!host.match(/(localhost|dev|demo|staging)/)) {
            throw new _errors.ImporterMetadataError(`This workbook can only be imported to ${homeServer} or a non-production (dev/demo/staging) server. (nb: current server is ${host})`);
        }
    }
    return importingToHome;
}
function ensureValidProgramMetadata(surveyMetadata) {
    if (surveyMetadata.some(({ sheetName })=>sheetName === 'Registry')) {
        throw new _errors.ImporterMetadataError('Cannot have a survey called "Registry"');
    }
    // Ensures complex chart import rules
    const containsComplexChart = surveyMetadata.some(({ surveyType })=>[
            _constants.SURVEY_TYPES.COMPLEX_CHART,
            _constants.SURVEY_TYPES.COMPLEX_CHART_CORE
        ].includes(surveyType));
    if (containsComplexChart) {
        const surveyTypeSummary = surveyMetadata.map(({ surveyType })=>surveyType).reduce((summary, type)=>{
            if (summary[type]) {
                summary[type]++;
            } else {
                summary[type] = 1;
            }
            return summary;
        }, {});
        const complexChart = surveyTypeSummary[_constants.SURVEY_TYPES.COMPLEX_CHART];
        const complexChartCore = surveyTypeSummary[_constants.SURVEY_TYPES.COMPLEX_CHART_CORE];
        const hasOnlyOneComplexSet = complexChart === 1 && complexChartCore === 1;
        if (complexChart && !complexChartCore) {
            throw new _errors.ImporterMetadataError('Complex charts need a core data set survey');
        }
        if (complexChartCore && !complexChart) {
            throw new _errors.ImporterMetadataError('Cannot import a complex chart core without the main survey');
        }
        if (hasOnlyOneComplexSet === false) {
            throw new _errors.ImporterMetadataError('Only one complex chart and complex chart core allowed in a program');
        }
    }
}
function readTwoModelTypeSheet(sheet, sheetName) {
    // The sheet follows this structure:
    // first few rows: data for the primary record (key in column A, value in column B)
    // then: secondary record header row (with name & code in columns A/B, then other keys)
    // then: secondary record values (corresponding to keys in the header row)
    const primaryRecord = {};
    // Read rows as part of the primary record until we hit the header row
    // (this should be within the first few rows, there shouldn't be that many keys and
    // there's no reason to add blank rows here)
    const headerRowIndex = (()=>{
        const rowsToSearch = 10;
        for(let i = 0; i < rowsToSearch; ++i){
            const cell = sheet[`A${i + 1}`];
            if (!cell) continue;
            if (cell.v === 'code' || cell.v === 'name') {
                // we've hit the header row -- immediately return
                return i;
            }
            const nextCell = sheet[`B${i + 1}`];
            if (!nextCell) continue;
            const cellKey = cell.v.trim();
            const rawValue = nextCell.v;
            primaryRecord[cellKey] = typeof rawValue === 'string' ? rawValue.trim() : rawValue;
        }
        // we've exhausted the search
        throw new _errors.ImporterMetadataError(`A survey workbook ${sheetName} sheet must have a row starting with a 'name' or 'code' cell in the first 10 rows`);
    })();
    return {
        primaryRecord,
        secondaryRecords: _xlsx.utils.sheet_to_json(sheet, {
            range: headerRowIndex
        })
    };
}
function readMetadata(metadataSheet) {
    _logging.log.debug('Checking for metadata sheet');
    if (!metadataSheet) {
        throw new _errors.ImporterMetadataError('A program workbook must have a sheet named Metadata');
    }
    _logging.log.debug('Reading metadata for survey header row');
    const { primaryRecord: metadata, secondaryRecords: surveyRows } = readTwoModelTypeSheet(metadataSheet, 'Metadata');
    if (!metadata.programCode) {
        throw new _errors.ImporterMetadataError('A program must have a code');
    }
    if (!metadata.programName) {
        throw new _errors.ImporterMetadataError('A program must have a name');
    }
    const importingToHome = checkHomeServer(metadata.homeServer);
    // Use a country prefix if we're importing to a server other than the home server.
    // eg a program will import as "(Samoa) NCD Screening" on the dev server, but
    // just "NCD Screening" on the Samoa server. Same goes for surveys.
    const { country } = metadata;
    const prefix = !importingToHome && country ? `(${country}) ` : '';
    const programName = `${prefix}${metadata.programName}`;
    const programId = `program-${(0, _idify.idify)(metadata.programCode)}`;
    const surveyMetadata = surveyRows.map((row)=>({
            ...row,
            // Note: __rowNum__ is a non-enumerable property, so needs to be accessed explicitly here
            // -1 as it'll have 2 added to it later but it's only 1 off
            rowIndex: row.__rowNum__ - 1,
            sheetName: row.name,
            id: `${programId}-${(0, _idify.idify)(row.code)}`,
            name: `${prefix}${row.name}`,
            programId
        })).filter(({ status, name, rowIndex })=>{
        // check against home server & publication status
        switch(status || 'draft'){
            case 'publish':
                return true;
            case 'hidden':
                return false;
            case 'draft':
                // import drafts only to non-home servers (ie dev servers)
                return !importingToHome;
            default:
                throw new _errors.ValidationError('Metadata', rowIndex, `Survey ${name} has invalid status ${status}. Must be one of publish, draft, hidden.`);
        }
    });
    ensureValidProgramMetadata(surveyMetadata);
    return {
        programRecord: {
            name: programName,
            id: programId
        },
        surveyMetadata
    };
}

//# sourceMappingURL=readMetadata.js.map