<template>
	<div v-if="options_med && inputs" class="row">
		<div class="col-12">
			<div class="mb-3">
				<ViewOrderableRawLookup :client="client" label="Orderable" dgnm="O RX" :query="options_med ? options_med.Medication.default.text : null" v-model="common.ORDERABLE" />
			</div>
		</div>
		<template v-for="(instance, idx) in inputs" :key="instance">
			<ViewOrderDialogMedOutptInstance :multi="inputs.length > 1" :more="idx + 1 < inputs.length" :dlgdef="dlgdef" :options_med="options_med" :options_schedule="options_schedule" :loadrsp_group="loadrsp_groups[idx]" v-model="inputs[idx]" @add="e => inputs.splice(idx + 1, 0, Object.assign({}, instance))" @remove="e => inputs.splice(idx, 1)" />
		</template>
		<div class="col-4">
			<div class="mb-3">
				<Autocomplete label="Indication" :items="options_med['Indication'].items" v-model="common.INDICATION" />
			</div>
		</div>
		<div class="col-8">
			<div class="form-floating mb-3">
				<input type="text" class="form-control" placeholder=" " v-model="common.COMMENT" />
				<label>Comment</label>
			</div>
		</div>
		<div class="col-2">
			<div class="form-floating mb-3">
				<input type="number" class="form-control" placeholder=" " v-model="common.SUPPLY" />
				<label>Days Supply</label>
			</div>
		</div>
		<div class="col-2">
			<div class="form-floating mb-3">
				<input type="number" class="form-control" placeholder=" " v-model="common.QTY" />
				<label>{{base_shortform ? 'Qty (in ' + base_shortform + ')' : 'Quantity'}}</label>
			</div>
		</div>
		<div class="col-2">
			<div class="form-floating mb-3">
				<input type="number" class="form-control" placeholder=" " v-model="common.REFILLS" />
				<label>Refills</label>
			</div>
		</div>
		<div class="col-3">
			<div class="form-floating mb-3">
				<select class="form-select" v-model="common.PICKUP">
					<option value="M">Mail</option>
					<option value="W">Window</option>
				</select>
				<label>Pickup</label>
			</div>
		</div>
		<div class="col-3">
			<div v-if="options_fill && options_fill.Priority && options_fill.Priority.items" class="form-floating mb-3">
				<select class="form-select" v-model="common.URGENCY"><option v-for="item in options_fill.Priority.items" :value="item.value">{{item.text}}</option></select>
				<label>Priority</label>
			</div>
		</div>
		<div class="col-10">
			<div class="card mb-3" style="background-color: #fdfbd7;"><div class="card-body" style="font-family: monospace; white-space: pre-wrap;">{{preview}}</div></div>
		</div>
		<div class="col-2">
			<div class="btn-group-vertical mb-3" style="width: 100%;">
				<button type="button" class="btn btn-primary" @click="e => $emit('submit', output)">Submit</button>
				<button type="button" class="btn btn-danger" @click="e => $emit('cancel')">Cancel</button>
			</div>
		</div>
	</div>
</template>

<script>
	import { debounce, groupByArray } from './util.mjs';
	import { translate } from './numberwords.mjs';

	import ViewOrderableRawLookup from './ViewOrderableRawLookup.vue';
	import Autocomplete from './Autocomplete.vue';
	import DateTimePicker from './DateTimePicker.vue';
	import ViewOrderDialogMedOutptInstance from './ViewOrderDialogMedOutptInstance.vue';

	const C_COMMON = ['ORDERABLE', 'INDICATION', 'COMMENT', 'SUPPLY', 'QTY', 'REFILLS', 'PICKUP', 'URGENCY'];

	const C_DAYS = {
		'': 1,
		'MONTH': 30,
		'WEEK': 7,
		'DAY': 1,
		'HOUR': 1/24,
		'MINUTE': 1/24/60
	};

	const C_WP = { '15': true, '758': true, '763': true };

	function input_dose_parse(value) {
		value = (value) && (value.indexOf('&') >= 0) ? value.split('&') : [parseFloat(value) || null, value ? value.replace(/^\s*([+-]?(?:\d+|\d+\.\d+))\s*|\s+$/g, '').toUpperCase() || null : null, null, null, value, null, null, null];
		value.dose = value[0];
		value.unit = value[1];
		value.count = value[2];
		value.form = value[3];
		value.text = value[4];
		value.id = value[5];
		value.base_dose = value[6];
		value.base_unit = value[7];
		return value;
	}

	function greatest_common_base(values, products) {
		for(var i = 0; i < values.length; ++i) {
			var value = values[i];
			if((isNaN(value.dose)) || (isNaN(parseFloat(value.dose)))) return;
			products = products.filter(x => (x.dose) && (x.unit == value.unit) && ((Math.abs((value.dose/x.dose)%1) < 0.001) || ((x.split == '1') && (Math.abs((value.dose/x.dose)%1 - 0.5) < 0.001))));
			if(products.length < 1) return;
		}
		return products.sort((a, b) => b.dose - a.dose)[0];
	}

	export default {
		components: {
			ViewOrderableRawLookup, Autocomplete, DateTimePicker, ViewOrderDialogMedOutptInstance
		},
		props: {
			client: Object,
			ien: String,
			dlgdef: Object,
			bldqrsp: Object,
			modelValue: Object
		},
		emits: [
			'submit',
			'cancel',
			'update:modelValue'
		],
		data() {
			return {
				loadrsp: null,
				loadrsp_groups: [],
				inputs: null,
				options_schedule: null,
				options_med: null,
				lastorderable: null,
				common: {}
			};
		},
		computed: {
			options_med_route() {
				if((this.options_med) && (this.options_med['Route'])) {
					var opt, rsp, res = this.options_med['Route'].items.slice();
					res.mapping = res.reduce((acc, val) => (acc[val.value] = val, acc), {});
					if((this.loadrsp) && (rsp = this.loadrsp['ROUTE']) && (!res.find(x => x.value == rsp.iValue))) res.push({ value: rsp.iValue, text: rsp.eValue, abbr: rsp.eValue, sig: rsp.eValue });
					return res;
				} else return [];
			},
			input_doses() {
				return this.inputs ? this.inputs.map(x => input_dose_parse(x.DOSE)) : [];
			},
			base_product() {
				return this.options_med ? greatest_common_base(this.input_doses, this.options_med['Dispense'].items) : undefined;
			},
			base_form() {
				try {
					return this.options_med['AllDoses'].items.find(x => x.id == this.base_product.id).dosefields.split('&')[3];
				} catch(ex) {}
			},
			base_shortform() {
				try {
					var dose_unit = this.base_product.dose + this.base_product.unit;
					return this.options_med['Dosage'].items.find(x => x.text == dose_unit).form;
				} catch(ex) {
					return this.base_form;
				}
			},
			sig() {
				if((this.options_med) && (this.inputs)) {
					var res = [];
					var verb = this.options_med['Verb'].default;
					var input_doses = this.input_doses;
					var base_product = this.base_product;
					var base_form = this.base_form;
					for(var i = 0; i < this.inputs.length; ++i) {
						var input = this.inputs[i], input_route = input.ROUTE, input_dose = input_doses[i];
						var route = (this.options_med_route.find(x => x.value == input_route) || { sig: input_route }).sig;
						var prep = this.options_med_route.mapping[input_route] ? this.options_med['Preposition'].default : null;
						var schedule = (this.options_schedule) && (this.options_schedule[input.SCHEDULE]) ? this.options_schedule[input.SCHEDULE].text : input.SCHEDULE;
						res.push((input_dose ? verb + ' ' + (base_product ? translate(input_dose.dose/base_product.dose).toUpperCase() + ' ' + (base_form || 'UNIT') + (input_dose.dose/base_product.dose >= 2 ? 'S' : '') : input_dose.text) : '') + (route ? ' ' + (prep ? prep + ' ' : '') + route : '') + (schedule ? ' ' + schedule : '') + (input.SCHTYPE == 'P' ? ' AS NEEDED' : '') + (input.DAYS ? ' FOR ' + input.DAYS : '') + (i + 1 >= this.inputs.length ? '' : (' ' + (input.CONJ == 'T' ? 'THEN' : input.CONJ == 'A' ? 'AND' : 'OR'))));
					}
					return res.join(' ');
				}
			},
			preview() {
				var base_product = this.base_product;
				var product = base_product ? base_product.text + '\n' : this.options_med ? this.options_med['Medication'].default.text + '\n' : '';
				return product + (this.sig ? this.sig + (this.common.COMMENT ? ' ' + this.common.COMMENT : '') + '\n' : '') + 'Quantity: ' + (+this.common.QTY) + ' Refills: ' + (+this.common.REFILLS) + (this.common.INDICATION ? '\nIndication: ' + this.common.INDICATION : '');
			},
			output() {
				if((this.dlgdef) && (this.inputs)) {
					var res = {};
					var inputs = this.inputs.length > 0 ? this.inputs.slice() : [{}];
					inputs[0] = this.common ? Object.assign({}, inputs[0], this.common) : Object.assign({}, inputs[0]);
					inputs[0].SIG = this.sig;
					if(this.base_product) {
						inputs[0].STRENGTH = this.base_product.dose + this.base_product.unit;
						inputs[0].DRUG = this.base_product.id;
					}
					for(var i = 0; i < inputs.length; ++i) {
						var seq = i + 1, instance = inputs[i];
						for(var j = 0, desc, val; j < this.dlgdef.length; ++j) {
							desc = this.dlgdef[j];
							if(val = instance[desc.promptID]) {
								if(C_WP[desc.promptIEN]) {
									res['"' + desc.promptIEN + '","' + seq + '"'] = 'ORDIALOG("WP",' + desc.promptIEN + ',' + seq + ')';
									res['"WP","' + desc.promptIEN + '","' + seq + '","1","0"'] = instance[desc.promptID];
								} else res['"' + desc.promptIEN + '","' + seq + '"'] = instance[desc.promptID];
							}
						}
					}
					return res;
				}
			}
		},
		created() {
			this.$watch(
				() => this.client,
				async () => {
					if(this.client) {
						this.options_schedule = await this.client.ORWDPS1_SCHALL('', 0);
						this.options_fill = await this.client.ORWDPS1_ODSLCT('O', '', '');
					} else this.options_schedule = this.options_fill = null;
				},
				{ immediate: true }
			);
			this.$watch(
				() => (this.client, this.dlgdef, this.bldqrsp, this.options_fill, {}),
				async () => {
					if((this.client) && (this.dlgdef) && (this.bldqrsp)) {
						this.inputs = [this.dlgdef.reduce((acc, val) => (acc[val.promptID] = acc[val.promptID], acc), { ORDERABLE: this.common ? this.common.ORDERABLE : null })];
						if(this.options_fill) {
							if((this.options_fill.Pickup) && (this.options_fill.Pickup.default)) this.inputs.PICKUP = this.options_fill.Pickup.default.value;
							if((this.options_fill.Refills) && (this.options_fill.Refills.default)) this.inputs.REFILLS = this.options_fill.Refills.default.value;
							if((this.options_fill.Priority) && (this.options_fill.Priority.default)) this.inputs.URGENCY = this.options_fill.Priority.default.value;
						}
						this.loadrsp_groups = [];
						if((this.bldqrsp.ResponseID) && (this.bldqrsp.ResponseID != '0')) {
							this.loadrsp = await this.client.ORWDX_LOADRSP(this.bldqrsp.ResponseID, 0, 0);
							if((this.loadrsp) && (this.loadrsp.length > 0)) {
								this.loadrsp_groups = groupByArray(this.loadrsp, 'instance').sort((a, b) => a.key - b.key).map(x => x.values.reduce((acc, val) => (acc[val.promptID] = val, acc), x.values));
								Object.assign(this.inputs[0], this.loadrsp_groups[0].reduce((acc, val) => (acc[val.promptID] = val.iValue != '^WP^' ? val.iValue : val.eValue, acc), {}));
								for(var i = 1; i < this.loadrsp_groups.length; ++i) this.inputs.push(this.loadrsp_groups[i].reduce((acc, val) => (acc[val.promptID] = val.iValue != '^WP^' ? val.iValue : val.eValue, acc), {}));
							}
						}
						this.common = C_COMMON.reduce((acc, val) => (acc[val] = this.inputs[0][val], acc), {});
					} else {
						this.inputs = this.loadrsp = null;
						this.loadrsp_groups = [];
					}
				},
				{ immediate: true }
			);
			this.$watch(
				() => (this.client, (this.common) && (this.common.ORDERABLE), {}),
				async () => {
					this.options_med = (this.client) && (this.common) && (this.common.ORDERABLE) ? await this.client.ORWDPS2_OISLCT(this.common.ORDERABLE, '', '', 'Y', '') : null;
				}
			);
			this.$watch(
				() => ((this.common) && (this.common.ORDERABLE), {}),
				() => {
					if((this.common) && (this.common.ORDERABLE)) {
						if((this.lastorderable) && (this.lastorderable != this.common.ORDERABLE)) {
							for(var k in this.common) if((k != 'ORDERABLE') && (this.common.hasOwnProperty(k))) this.common[k] = null;
							this.inputs = [{}];
							this.loadrsp_groups = [];
						}
						this.lastorderable = this.common.ORDERABLE;
					}
				},
				{ immediate: true }
			);
			this.$watch(
				() => this.inputs ? this.inputs.map(x => x.DAYS ? parseFloat(x.DAYS)*C_DAYS[x.DAYS.replace(/^\s*([+-]?(?:\d+|\d+\.\d+))\s*|S\b|\s+$/g, '')] : 0).reduce((acc, val) => acc + val, 0) : 0,
				(value) => { this.common.SUPPLY = value; },
				{ immediate: true }
			);
			this.$watch(
				() => (this.inputs) && (this.inputs.length > 0) && (this.base_product) && (this.common.SUPPLY > 0) ? this.inputs.map(x => [(x.DOSE) && (x.DOSE).indexOf('&') >= 0 ? x.DOSE.split('&')[2] : '~', x.SCHEDULE || '~', x.DAYS || '~']).reduce((acc, val) => (acc[0] += val[0] + '^', acc[1] += val[1] + '^', acc[2] += val[2] + '^', acc), ['', '', '']) : null,
				debounce(async (value) => {
					if(value) {
						var res = await this.client.ORWDPS2_DAY2QTY(this.common.SUPPLY, value[0], value[1], value[2], '', '');
						if(!isNaN(parseFloat(res))) this.common.QTY = res;
					};
				}, 500),
				{ immediate: true }
			);
			this.$watch(
				() => { return { dlgdef: this.dlgdef, inputs: this.inputs, common: this.common, sig: this.sig }; },
				debounce(() => this.$emit('update:modelValue', this.output), 100),
				{ deep: true, immediate: true }
			);
		}
	};
</script>
