<template>

    <div class="bmiCalculator" :class="[errorClass]">

		<div class="bmiCalculator__bmi">

			<div class="bmiCalculator__unitType">

				<div class="row">

					<div class="optionButtons radioButtons">

						<div class="labelButton">

							<input type="radio"
								   :name="questionName + '[bmi][type]'"
								   :id="'question_' + question.id + 'bmi_type_metric'"
								   value="Metric"
								   v-model="type"
								   :checked="isType('Metric')"
							/>

							<label
									:for="'question_' + question.id + 'bmi_type_metric'"
							>
								Metric
							</label>

						</div> <!-- .labelButton -->

						<div class="labelButton">

							<input type="radio"
								   :name="questionName + '[bmi][type]'"
								   :id="'question_' + question.id + 'bmi_type_imperial'"
								   value="Imperial"
								   v-model="type"
								   :checked="isType('Imperial')"
							/>

							<label
									:for="'question_' + question.id + 'bmi_type_imperial'"
							>
								Imperial
							</label>

						</div> <!-- .labelButton -->

					</div> <!-- .optionButtons -->

				</div> <!-- .row -->

			</div><!-- .bmiUnitType -->

			<div class="bmiCalculator__fieldWrap">

				<div class="bmiCalculator__fields bmiCalculator__fields--metric" v-show="isType('Metric')">

					<fieldset class="bmiCalculator__fieldset">

						<legend>Height</legend>

						<div class="row">

							<div class="inputWrap">

								<label
										:for="'question_' + question.id + '_bmi_height_cm'"
								>cm</label>

								<input
										:id="'question_' + question.id + '_bmi_height_cm'"
										type="number"
										step="1"
										min="0"
										max="300"
										:name="'questions[' + question.id + '][bmi][metric][height_cm]'"
										v-model="heightCm"
										@input="update('heightCm')"
										@change="heightCmChanged = true;"
								>

							</div> <!-- .inputWrap -->

						</div> <!-- .row -->

					</fieldset>

					<fieldset class="bmiCalculator__fieldset">

						<legend>Weight</legend>

						<div class="row">

							<div class="inputWrap">

								<label
										:for="'question_' + question.id + '_bmi_height_kg'"
								>kg</label>

								<input
										:id="'question_' + question.id + '_bmi_height_kg'"
										type="number"
										step="1"
										min="0"
										max="800"
										:name="'questions[' + question.id + '][bmi][metric][weight_kg]'"
										v-model="weightKg"
										@input="update('weightKg')"
										@change="weightKgChanged = true;"
								>

							</div> <!-- .inputWrap -->

						</div> <!-- .row -->

					</fieldset>

				</div> <!-- .bmiCalculator__fields--metric -->


				<div class="bmiCalculator__fields bmiCalculator__fields--imperial" v-show="isType('Imperial')">

					<fieldset class="bmiCalculator__fieldset">

						<legend>Height</legend>

						<div class="row">

							<div class="inputWrap">

								<label
										:for="'question_' + question.id + '_bmi_height_feet'"
								>feet</label>

								<input
										:id="'question_' + question.id + '_bmi_height_feet'"
										type="number"
										step="1"
										min="0"
										max="10"
										:name="'questions[' + question.id + '][bmi][imperial][height_feet]'"
										v-model="heightFeet"
										@input="update('heightFeet')"
								>

							</div> <!-- .inputWrap -->

							<div class="inputWrap">

								<label
										:for="'question_' + question.id + '_bmi_height_inches'"
								>inches</label>

								<input
										:id="'question_' + question.id + '_bmi_height_inches'"
										type="number"
										step="1"
										min="0"
										max="12"
										:name="'questions[' + question.id + '][bmi][imperial][height_inches]'"
										v-model="heightInches"
								>

							</div> <!-- .inputWrap -->

						</div> <!-- .row -->

					</fieldset>

					<fieldset class="bmiCalculator__fieldset">

						<legend>Weight</legend>

						<div class="row">

							<div class="inputWrap">

								<label
										:for="'question_' + question.id + '_bmi_height_stone'"
								>stone</label>

								<input
										:id="'question_' + question.id + '_bmi_height_stone'"
										type="number"
										step="1"
										min="0"
										max="100"
										:name="'questions[' + question.id + '][bmi][imperial][weight_stone]'"
										v-model="weightStone"
										@input="update('weightStone')"
								>

							</div> <!-- .inputWrap -->

							<div class="inputWrap">

								<label
										:for="'question_' + question.id + '_bmi_height_pounds'"
								>pounds</label>

								<input
										:id="'question_' + question.id + '_bmi_height_pounds'"
										type="number"
										step="1"
										min="0"
										max="13"
										:name="'questions[' + question.id + '][bmi][imperial][weight_pounds]'"
										v-model="weightPounds"
								>

							</div> <!-- .inputWrap -->

						</div> <!-- .row -->

					</fieldset>

				</div> <!-- .bmiCalculator__fields--imperial -->

			</div><!-- .bmiCalculator__fieldWrap -->

		</div><!-- .bmiCalculator__bmi -->

		<div class="bmiCalculator__ethnicity">

			<div class="bmiCalculator__ethnicity__title">

				<div class="row">

					<div class="labelButton">
						<h4>Ethnicity</h4>
						<p>Entering this information will allow us to give you more accurate advice about your BMI.</p>
					</div>

				</div> <!-- .row -->

			</div><!-- .bmiCalculator__ethnicity__title -->

			<div class="bmiCalculator__ethnicity__selection">

				<div class="bmiCalculator__ethnicity__selection__select">

					<div class="row bmiCalculator__ethnicity__selection__row">

						<select

							class="bmiCalculator__ethnicity__selection__select__element default"
							v-model.number="ethnicityIdSelected"
							@change="onEthnicityChange"

						>

							<option value="-1">Select your ethnicity</option>

							<option
								v-for="(option, index) in ethnicities"
								:key="option.id"
								:value="option.ethnicity_id"
								v-html="option.ethnicity_name"
							></option>

						</select>

					</div><!-- .bmiCalculator__ethnicity__selection__row -->

					<div class="bmiCalculator__ethnicity__selection__description" v-if="ethnicityActive.ethnicity_id > -1">

						<p v-html="ethnicityActive.ethnicity_description"></p>

					</div><!-- .bmiCalculator__ethnicity__selection__description -->

				</div><!-- .bmiCalculator__ethnicity__selection__select -->

				<input
					type="hidden"
					v-model="ethnicitySelectedName"
					:name="questionName + '[bmi][ethnicity][name]'"
				>

				<input
					type="hidden"
					v-model="categoryInRange.bmi_category"
					:name="questionName + '[bmi][ethnicity][category]'"
				>

				<input
					type="hidden"
					v-model="ethnicityIdSelected"
					:name="questionName + '[bmi][ethnicity][id]'"
				>


			</div><!-- .bmiCalculator__ethnicity__selection -->

		</div><!-- .bmiCalculator__ethnicity -->

        <div class="bmiCalculation" v-show="showBmiCalculation">

			<div class="bmiCalculation__value">
				Your BMI is: <span v-html="bmiCalculation"></span>
			</div><!-- .bmiCalculation__value -->

			<div class="bmiCalculation__category" v-if="categoryInRange?.bmi_category?.length">
				Category: <span v-html="categoryInRange.bmi_category"></span>
			</div><!-- .bmiCalculation__category -->

            <input
                    type="hidden"
                    v-model="bmiCalculation"
                    :name="questionName + '[bmi][value]'"
            >

        </div><!-- .bmiCalculation -->


    </div> <!-- .bmiCalculator -->

</template>

<script>


import { props, computed, methods } from "../mixins/fields";
import { debounce } from 'lodash';

export default {

    name: 'bmiCalculator',

    mixins: [props, computed, methods],

    props: {
        setType: {
            type: [String], //'Metric' || 'Imperial'
            default (rawProps) {
                return 'Metric';
            }
        },
        setHeightCm: {
            type: [Number],
            default (rawProps) {
                return 0;
            }
        },
        setWeightKg: {
            type: [Number],
            default (rawProps) {
                return 0;
            }
        },
        setHeightFeet: {
            type: [Number],
            default (rawProps) {
                return 0;
            }
        },
        setHeightInches: {
            type: [Number],
            default (rawProps) {
                return 0;
            }
        },
        setWeightStone: {
            type: [Number],
            default (rawProps) {
                return 0;
            }
        },
        setWeightPounds: {
            type: [Number],
            default (rawProps) {
                return 0;
            }
        }
    },

    data() {

        return {

            type: 'Metric', //'Metric' || 'Imperial'
            heightCm: 0,
            weightKg: 0,
            heightFeet: 0,
            heightInches: 0,
            weightStone: 0,
            weightPounds: 0,
            currentBMIValue: 0,
            changed: {
                heightCm: false,
                weightKg: false,
                heightFeet: false,
                weightStone: false
            },
			ethnicityIdSelected: -1,
			errorType: ''
        }

    },

    created() {

        this.type = this.setType;
        this.heightCm = this.setHeightCm;
        this.weightKg = this.setWeightKg;
        this.heightFeet = this.setHeightFeet;
        this.heightInches = this.setHeightInches;
        this.weightStone = this.setWeightStone;
        this.weightPounds = this.setWeightPounds;

        // Mark fields as changed if restored from draft so updateAllowed() passes
        if (this.isType('Metric')) {
            if (this.heightCm > 0) this.changed.heightCm = true;
            if (this.weightKg > 0) this.changed.weightKg = true;
        } else {
            if (this.heightFeet > 0) this.changed.heightFeet = true;
            if (this.weightStone > 0) this.changed.weightStone = true;
        }

        // Restore ethnicity selection if provided via bmi_field_values
        if (this.question?.bmi_field_values?.ethnicity) {
            this.ethnicityIdSelected = parseInt(this.question.bmi_field_values.ethnicity, 10);
        }

    },

    computed: {

		//Used to show bmi value when available
		showBmiCalculation() {

			return this.bmiCalculation > 0 && !this.question.settings.hidden_input && this.ethnicityIdSelected > -1;

		},

		//Build the BMI value
        bmiCalculation() {

            let height = 0,
                weight = 0;

            if(this.isType('Metric')) {
                height = parseInt(this.heightCm);
                weight = parseInt(this.weightKg);
            }else{

                if(parseInt(this.heightFeet) > 0) {
                    let totalInches = (parseInt(this.heightFeet) * 12) + parseInt(this.heightInches);
                    height = (totalInches * 2.54);
                }

                if(parseInt(this.weightStone) > 0) {
                    let totalPounds = (parseInt(this.weightStone) * 14) + parseInt(this.weightPounds);
                    weight = (totalPounds * 0.453592);
                }
            }

            if(weight > 0 && height > 0) {
                return (weight / Math.pow((height / 100), 2)).toFixed(2);
            }else{
                return 0;
            }

        },

		//Can be used to block the user if there is a minimum required bmi value to continue
		minBMI() {

			let cats = this.ethnicityActive.categories;

			if(cats.length) {

				let lowest = -1;

				cats.forEach(cat => {

					let low = parseInt(cat.cutoff_low);

					if(lowest < 0) {
						lowest = low;
					}

					if(!isNaN(lowest)) {

						if(low < lowest) {
							lowest = low;
						}

					}

				});

				return lowest;

			}

			return 0;

		},

		//Find the first ethnicity category in range of the cut off points
		categoryInRange() {

			const category = this.ethnicityActive.categories.filter(cat => {

				let high = parseInt(cat.cutoff_high),
					low = parseInt(cat.cutoff_low);

				high = isNaN(high) ? 9999 : high;
				low = isNaN(low) ? 0 : low;


				if(this.bmiCalculation >= low && this.bmiCalculation < high) {
					return cat;
				}

				return false;


			});

			if(category.length) {
				return category[0];
			}

			return false;

		},

		//Return a list of the bmi ethnicities available
		ethnicities() {
			return this.question?.bmi_ethnicities?.length ? this.question.bmi_ethnicities : [];
		},

		//Return the active ethnicity object
		ethnicityActive() {


			const selected = this.ethnicities.filter(ethnicity => ethnicity.ethnicity_id == this.ethnicityIdSelected);


			if(selected.length) {
				return selected[0];
			}

			return {
				categories: [],
				ethnicity_description: '',
				ethnicity_id: -1,
				ethnicity_name: 'Unselected'

			};


		},

		//Return the name of the currently selected ethnicity name
		ethnicitySelectedName() {

			return this.ethnicityActive.ethnicity_name;

		},

		//Return a unique component id
		uniqueId() {
			return this._uid;
		},

		//Add internal error classes
		errorClass() {

			if(this.errorType.length) {
				return 'bmiCalculator__error bmiCalculator__error--' + this.errorType;
			}

			return '';
		}

    },

    watch: {

		//Update when bmi changes
		bmiCalculation(value, oldValue) {

			let val = parseFloat(value);

			if(!isNaN(val)) {
				this.currentBMIValue = val;
			}else{
				this.currentBMIValue = 0;
			}

			this.update(false, true);
		}

    },

    methods: {


		//Determine imperial and metric types
        isType(unitType) {
            return this.type.toLowerCase() == unitType.toLowerCase();
        },

        // Sync ethnicity into bmi_field_values so the merge in update()
        // always carries the latest selection, then notify the parent.
        onEthnicityChange() {
            if (this.question.bmi_field_values) {
                this.question.bmi_field_values.ethnicity = this.ethnicityIdSelected;
            }
            this.updateQuestion(this.question);
        },

        update(type) {

            const _this = this;

            this.changed[type] = true;


            if( this.updateAllowed() ) {


                this.$nextTick(() => {

                    _this.question.answer = _this.currentBMIValue;

                    // Merge into existing bmi_field_values to preserve ethnicity
                    // and other keys that may have been set by created() or the
                    // server-side draft restore — avoids a race where update()
                    // overwrites the object before ethnicity has been carried over.
                    _this.question.bmi_field_values = {
                        ...(_this.question.bmi_field_values || {}),
                        height_cm: parseInt(this.heightCm),
                        weight_kg: parseInt(this.weightKg),
                        height_feet: parseInt(this.heightFeet),
                        height_inches: parseInt(this.heightInches),
                        weight_stone: parseInt(this.weightStone),
                        weight_pounds: parseInt(this.weightPounds),
                        type: this.type,
                    };

                    _this.updateQuestion(_this.question);

                });

            }

        },

        updateAllowed() {

            if(this.isType('Metric')) {

                if(this.changed.heightCm && this.changed.weightKg) {
                    return true;
                }

            }else if(this.isType('Imperial')) {

                if(this.changed.heightFeet && this.changed.weightStone) {
                    return true;
                }

            }

            return false;

        },

        updateQuestion: debounce(function(question, inputEvent) {

			this.errorType = '';

            if(typeof inputEvent == 'undefined' || this.allowInputEvent) {
                question = this.validate(question);
                this.$emit('update-question', question);
            }

        }, 200),

        validate(question) {

            let canProceed = true;

            if ((!question.answer > 0 && question.is_required) || (this.ethnicityIdSelected < 0 && question.is_required )) {

                canProceed = false;

				if(this.ethnicityIdSelected < 0 && !question.answer > 0) {
					this.errorType = 'all';
				}else if(this.ethnicityIdSelected < 0) {
					this.errorType = 'ethnicity';
				}else{
					this.errorType = 'bmi';
				}

            }

            question.can_proceed = canProceed;

            return question;

        }

    }
}
</script>

<style lang="less">

	.bmiCalculator {

        width: 100%;
        position: relative;

        &__fieldWrap {

            padding: 12px 0 0;
            margin: 24px 0 0;
            border-top: 1px solid var(--border_color);

            @media @mobile {
                padding: 20px 0 0;
            }
        }

        .bmiCalculation {

            padding: 20px;
            margin: 24px 0 0;
            border: 1.5px solid var(--border_color_dark);
            .rems(14);
            line-height: 1.2em;
            font-weight: 600;
            border-radius: 5px;

            span {
                font-weight: normal;
            }

        }

        &__fields {

            .row {
                display: flex;
                flex-direction: column;
                flex-wrap: wrap;
                gap: 0 16px;

                @media @mobile {
                    flex-wrap: wrap;
                    gap: 0;
                }

                &:before, &:after {
                    display: none;
                }
            }

            .inputWrap {

                position: relative;
                float: none;
                clear: both;
                padding: 0;
                flex: 1 1 100%;
                margin: 0 0 12px 0;

                &:last-child {
                    margin: 0;
                }

                @media @mobile {
                    flex: 0 0 100%;
                    margin-bottom: 12px;

                    &:last-child {
                        margin-bottom: 0;
                    }
                }

                input {
                    position: relative;
                    z-index: 1;
                    float: none !important;
                    clear: both !important;
                    padding-right: 64px !important;
                    -moz-appearance: textfield;
                    border-radius: 59px;

                    /* Chrome, Safari, Edge, Opera */
                    &::-webkit-outer-spin-button,
                    &::-webkit-inner-spin-button {
                        -webkit-appearance: none;
                        margin: 0;
                    }

                }

                label {
                    background: var(--primary_color);
                    color: #fff;
                    font-weight: 700;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    padding: 4px;
                    width: 64px;
                    height: ~"calc(100% - 2px)";
                    position: absolute;
                    top: 1px;
                    right: 1px;
                    bottom: 1px;
                    z-index: 2;
                    border-radius: 0 59px 59px 0;
                    .rems(12);
                    line-height: normal;
                    margin: 0;

                }
            }
        }

        fieldset {

            legend {

                display: block;
                .rems(17);
                line-height: 1.2em;
                font-weight: 700;
                color: var(--text_color);
                margin: 0 0 8px;

            }

        }

        .row {

            .radioButtons {

                .labelButton {

                    label {
                        border-radius: 59px !important;
                    }

                }

            }

			& > .inputWrap {

				margin: 0 0 12px;

				&:last-child {

					margin: 0;

				}

			}

        }

		&__error {

			&--bmi, &--all {

				.bmiCalculator__fieldset {

					.row {
						input:not([type='checkbox']), .row input:not([type='radio']) {

							border-color: var(--alert_color);

						}
					}
				}

			}

			&--ethnicity, &--all {

				.bmiCalculator__ethnicity__selection__select__element {

					border-color: var(--alert_color);
				}

			}


		}

    }

</style>
