<template>

    <div class="gpSearchWrap">

        <div class="searchBoxWrap" :class="[searchFocused ? 'searchFocused' : '']">

            <div class="row">

                <input type="search"
                       name="gp-search-term"
                       v-model="term"
                       :placeholder="searchPlaceholder"
                       @keyup="search()"
                       class="searchBox"
                       @focus="searchFocused = true"
                       @blur="searchFocused = false"
                />

                <button
                        type="button"
                        class="searchBoxIcon"
                        @click="clearSearch()"
                        v-if="isSearching"
                >

                    <font-awesome-icon :icon="['far', 'xmark']" />

                </button>

                <button
                        type="button"
                        class="searchBoxIcon"
                        @click="search()"
                        v-else
                >

                    <font-awesome-icon :icon="['far', 'magnifying-glass']" />

                </button>

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

            <div class="searchResultsBox" v-if="isSearching">

                <div class="loadingMessage" v-if="loading">

                    <loading-spinner
                            :loading="loading"
                            loading-text="Loading GP search results"
                    ></loading-spinner>

                </div> <!-- .loadingMessage -->

                <div class="searchResultsWrap" v-else>

                    <ul class="searchResults" v-if="hasSearchResults">

                        <template v-for="surgeryOption in results">
                            <li :key="'surgery' + surgeryOption.id">

                                <a
                                        href="#"
                                        v-html="surgeryAddress(surgeryOption)"
                                        :title="'Click to select: ' + surgeryAddress(surgeryOption)"
                                        @click.prevent="selectSurgery(surgeryOption)"
                                ></a>

                            </li>
                        </template>

                    </ul>

                    <div class="noResults" v-else>
                        <p>No surgeries found</p>
                    </div> <!-- .noResults -->

                </div> <!-- .searchResultsWrap -->

            </div> <!-- .searchResults -->


        </div> <!-- .searchBoxWrap -->

        <div class="editableOption">

            <div class="row">

                <input
                        type="checkbox"
                        v-model="editable"
                        :id="'editable' + '-' + instanceId"
                >
                <label :for="'editable' + '-' + instanceId" v-html="surgery.manual_doctor_surgery.label"></label>

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

        </div> <!-- .editableOption -->

        <div class="surgerySelected" v-if="!surgeryIsEmpty() || editable" v-cloak>

            <div class="surgeryBox" v-show="!editable">

                <button
                        type="button"
                        class="closeButton"
                        @click.prevent="removeSurgery()"

                >
                    <span class="visuallyHidden">Clear Address</span>
                    <font-awesome-icon :icon="['far', 'trash']" />
                </button>

                <h4>Selected surgery</h4>

                <template v-for="(fieldName, index) in surgeryProps(surgery)">

                    <div
                            class="surgeryText"
                            v-if="isVisibleField(fieldName)"
                    >

                        <span
                                class="textLabel"
                                v-html="surgery[fieldName].label + ':'"
                        ></span>

                        <span
                                class="textValue"
                                v-html="surgery[fieldName].value"
                                v-if="surgery[fieldName]?.value?.length"
                        ></span>

                        <span
                                class="textValue"
                                v-else
                        >N/A</span>

                    </div>

                </template>

            </div> <!-- .surgeryBox -->

            <div class="surgeryBox surgeryAddressFields" v-show="editable">

                <h4>Enter your GP surgery address</h4>

                <template v-for="(fieldName, index) in surgeryProps(surgery)">

                    <div class="row" v-if="isVisibleField(fieldName)" :class="[!surgery[fieldName].isValid ? 'errorWrap' : '']">

                        <div class="inputWrap">

                            <label
                                    :for="surgery.id.value + '_' + index + '_' + fieldName"
                                    v-html="surgery[fieldName].label"
                            ></label>

                            <input
                                    type="text"
                                    v-model="surgery[fieldName].value"
                                    :name="'doctor_surgery' + '[' + fieldName + ']'"
                                    :id="surgery.id.value + '_' + index + '_' + fieldName"
                                    :ref="'input_' + fieldName"
                                    @keyup="surgery[fieldName].isValid = true"
                            >

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

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

                    <div class="hiddenFields" v-else>

                        <input
                                type="hidden"
                                v-model="surgery[fieldName].value"
                                :name="'doctor_surgery' + '[' + fieldName + ']'"
                                :id="surgery.id.value + '_' + index + '_' + fieldName"
                        >

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

                </template>

                <div class="errorBox" v-if="!fieldsAreValid">

                    <template v-for="(fieldName, index) in surgeryProps(surgery)">

                        <div class="error" v-if="!surgery[fieldName].isValid">
                            <p v-html="surgery[fieldName].validationMessage"></p>
                        </div> <!-- .error -->

                    </template>

                </div> <!-- .errorBox -->

                <div class="buttonActions">

                    <button
                            type="button"
                            class="button"
                            @click.prevent="setEnteredAddress()"
                            aria-label="Click here to set your address"
                    >
                        Update address
                    </button>

                </div> <!-- .buttonActions -->

            </div><!-- .surgeryBox -->

        </div> <!-- .surgerySelected -->

        <div class="surgeryEmpty" v-else>
            <h4>Please use the search above to find your GP's surgery or enter the address manually.</h4>
        </div> <!-- .surgeryEmpty -->

    </div> <!-- .gpSearchWrap -->

</template>

<script>

import axios from 'axios';
import { debounce } from 'lodash';

export default {
    name: 'gpSurgerySearch',
    components: {

    },
    props: {
        instanceId: {
            type: [String, Number],
            default (rawProps) {
                return '1';
            }
        },
        searchUrl: {
            type: [String],
            default (rawProps) {
                return '';
            }
        },
        searchPlaceholder: {
            type: [String, Boolean],
            default (rawProps) {
                return 'Search Doctor Surgeries'
            }
        },
        userSurgery: {
            type: [Object],
            default (rawProps) {
                return {
                    practice_name: '',
                    address_1: '',
                    address_2: '',
                    address_3: '',
                    city: '',
                    postcode: '',
                    phone: '',
                    id: '',
                    manual_doctor_surgery: false
                };
            }
        }
    },
    data() {
        return {
            term: '',
            results: [],
            surgery: {},
            loading: false,
            resultsVisible: false,
            surgeryFields: {
                practice_name: {
                    label: 'Practice name',
                    value: '',
                    validate: false,
                    isValid: true,
                    validationMessage: ''
                },
                address_1: {
                    label: 'Address line 1',
                    value: '',
                    validate: true,
                    isValid: true,
                    validationMessage: 'Please enter a valid address'
                },
                address_2: {
                    label: 'Address line 2',
                    value: '',
                    validate: false,
                    isValid: true,
                    validationMessage: ''
                },
                address_3: {
                    label: 'Address line 3',
                    value: '',
                    validate: false,
                    isValid: true,
                    validationMessage: ''
                },
                city: {
                    label: 'City',
                    value: '',
                    validate: true,
                    isValid: true,
                    validationMessage: 'Please enter a valid city'
                },
                postcode: {
                    label: 'Postcode',
                    value: '',
                    validate: true,
                    isValid: true,
                    validationMessage: 'Please enter a valid postcode'
                },
                phone: {
                    label: 'Phone number',
                    value: '',
                    validate: false,
                    isValid: true,
                    validationMessage: ''
                },
                id: {
                    label: 'ID',
                    value: '',
                    validate: false,
                    isValid: true,
                    validationMessage: ''
                },
                manual_doctor_surgery: {
                    label: "Can't find your GP surgery? Please check this box to enter it manually.",
                    value: false,
                    validate: false,
                    isValid: true,
                    validationMessage: ''
                }
            },
            fieldsAreValid: true,
            searchFocused: false,
            editable: false
        }
    },
    created() {

        const _this = this;

        for(const prop in this.surgeryFields) {
            _this.surgery[prop] = _this.surgeryFields[prop];
        }

        for(const prop in this.userSurgery) {
            if(typeof _this.surgery[prop] != 'undefined') {
                _this.surgery[prop].value = this.userSurgery[prop];
            }
        }

        if(this.surgery?.address_1?.value.length) {
            this.fieldsAreValid = this.validateFields();
        }

    },
    computed: {

        hasSearchResults() {

            if(typeof this.results != 'undefined') {
                if(this.results.length) {
                    return true;
                }
            }

            return false;
        },

        isSearching() {
            return this.term.length && this.resultsVisible;
        }

    },
    methods: {

        search: debounce(function() {

            const _this = this,
                    formURL = this.formURL();

            if(formURL) {

                this.results = [];
                this.loading = true;
                this.resultsVisible = true;

                axios.get(formURL)
                .then(function (response) {

                    if(response?.data?.status == 'ok') {

                        const surgeries = response?.data?.doctor_surgeries;

                        if(surgeries) {
                            _this.results = _this.cleanResults(surgeries);
                        }

                    }

                })
                .catch(function (error) {
                    _this.results = [];
                })
                .finally(function () {
                    _this.loading = false;
                });

            }

        }, 200),

        validateField(field) {

            let validate = this.surgery[field]?.validate;

            if(validate) {

                switch(field) {

                    case 'address_1':
                        return this.surgery[field]?.value?.length > 3
                        break;
                    case 'city':
                        return this.surgery[field]?.value?.length > 2
                        break;
                    case 'postcode':
                        return this.surgery[field]?.value?.length > 5
                        break;

                }


            }

            return true;

        },

        validateFields() {

            const _this = this;
            let fieldsAreValid = true;

            for(const field in this.surgery) {

                let fieldIsValid = _this.validateField(field);

                if(!fieldIsValid) {
                    fieldsAreValid = false;
                    _this.surgery[field].isValid = false;
                }else{
                    _this.surgery[field].isValid = true;
                }

            }

            return fieldsAreValid;

        },

        setEnteredAddress() {

            this.fieldsAreValid = this.validateFields();

            if(this.fieldsAreValid) {
                this.editable = false;
                this.emitUpdate();
            }


        },

        emitUpdate() {

            let address = this.surgeryAddress(this.surgery);

            //Check for required fields validation
            let fieldValid = this.validateFields();

            if(!fieldValid) {
                address = '';
            }

            let surgeryClean = false;

            if(address.length) {
                surgeryClean = this.cleanSurgeryObject(this.surgery);
            }

            this.$emit('address-updated', surgeryClean);

        },

        cleanSurgeryObject(surgery) {

            let surgeryClean = {};

            for(const prop in surgery) {

                if(surgery[prop].hasOwnProperty('value')) {
                    surgeryClean[prop] = surgery[prop].value;
                }else{
                    surgeryClean[prop] = surgery[prop];
                }

            }

            return surgeryClean;

        },

        editableSurgery() {
            return this.surgery.manual_doctor_surgery === true || this.surgery.manual_doctor_surgery === 1 || this.surgery.manual_doctor_surgery == "1";
        },

        isVisibleField(fieldName) {

            return ['id', 'manual_doctor_surgery'].indexOf(fieldName) < 0;

        },

        surgeryProps(surgery) {

            let fields = [];

            for(const prop in this.surgeryFields) {
                fields.push(prop);
            }

            return fields;

        },

        clearSearch() {
            this.term = '';
            this.results = [];
            this.loading = false;
            this.resultsVisible = false;
        },

        //Convert surgery to address string
        surgeryAddress(surgery) {

            let addressString = '';

            if(!surgery || typeof surgery == 'undefined') {
                return addressString;
            }

            surgery = this.cleanSurgeryObject(surgery);

            let x = 0;
            for(const prop in surgery) {

                if(prop != 'id' && prop != 'manual_doctor_surgery') {

                    if(typeof surgery[prop] != 'undefined') {


                        if (surgery[prop].length) {

                            let str = '';

                            if (x > 0) {
                                str += ', '
                            }

                            str += surgery[prop];

                            addressString += str;

                            x++;

                        }

                    }

                }
            }

            return addressString;

        },

        selectSurgery(surgery) {

            this.resultsVisible = false;

            for(const prop in this.surgery) {
                this.surgery[prop].value = '';
            }

            for(const prop in this.surgeryFields) {
                if(surgery.hasOwnProperty(prop)) {
                    this.surgery[prop].value = surgery[prop];
                }
            }


            this.emitUpdate();

        },

        formURL() {

            if(this.searchUrl.length && this.term.length) {
                return this.searchUrl + '?term=' + this.term;
            }

            return false;
        },

        cleanResults(surgeries) {

            const allowedProps = [];

            for(const prop in this.surgeryFields) {
                allowedProps.push(prop);
            }

            let cleanSurgeries = surgeries.map(surgery => {

                let clean = {};

                for(const prop in surgery) {
                    if(allowedProps.indexOf(prop) > -1) {
                        clean[prop] = surgery[prop];
                    }
                }

                clean.manual_doctor_surgery = false;

                return clean;

            });

            return cleanSurgeries;

        },

        removeSurgery() {

            const _this = this;

            for (const prop in this.surgery) {
                _this.surgery[prop].value = '';
            }

            this.emitUpdate();
        },

        surgeryIsEmpty() {

            const _this = this;
            let isEmpty = true;

            for (const prop in this.surgery) {

                if(_this.surgery[prop]?.value?.length) {

                    if(prop != 'id' && prop != 'manual_doctor_surgery') {
                        isEmpty = false;
                    }

                }

            }

            return isEmpty;

        }

    }
}
</script>

<style lang="less">

    .gpSearchWrap {

        .searchBoxWrap {

            position: relative;

            & > .row {

                display: block;
                position: relative;
                float: none;
                clear: both;
                margin: 0;
                padding: 0;

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

                input[type=text] , input[type=search] {
                    position: relative;
                    z-index: 1;
                    float: none;
                    clear: both;
                    padding-right: 48px !important;
                    border-color: var(--primary_color);

                }

                .searchBoxIcon {

                    display: flex;
                    align-items: center;
                    justify-content: center;
                    position: absolute;
                    right: 0;
                    top: 0;
                    bottom: 0;
                    width: 48px;
                    height: 100%;
                    z-index: 2;
                    background: transparent;
                    border: transparent;
                    color: var(--text_color);
                    transition: color 200ms linear;
                    cursor: pointer;

                    &:hover, &:focus, &:active {
                        color: var(--highlight_color);
                        background: transparent;
                        border: transparent;
                        transition: color 200ms linear;
                    }

                    svg {
                        width: 16px;
                        height: 16px;
                    }
                }
            }

            &.searchFocused {

                .searchResultsBox {
                    border-color: color-mix(in srgb, var(--primary_color), var(--black_color) 8%) !important;
                }

            }

        }

        .searchResultsBox {
            display: block;
            width: 100%;
            position: absolute;
            left: 0;
            right: 0;
            border: 1px solid var(--primary_color);
            border-top: none;
            border-radius: 0 0 5px 5px;
            background: #fff;
            z-index: 3;
            margin-top: -5px;
            transition: border-color 200ms linear;

            &:before {
                content: "";
                position: absolute;
                top: 0;
                left: 0;
                right: 0;
                height: 1px;
                width: 100%;
                background: rgba(0,0,0,0.24);
                pointer-events: none;
                z-index: 1;
            }

        }

        .searchResultsWrap {
            width: 100%;
            height: auto;
            max-height: 190px;
            overflow: auto;
            padding: 20px;
        }

        .searchResults {

            width: 100%;
            height: auto;
            text-align: left !important;

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


            a {
                .rems(12);
                line-height: 1.2em;
                font-weight: 600;
                color: var(--text_color);
                text-transform: none;
                transition: color 200ms linear;
                display: block;
                padding: 12px 0;

                &:hover, &:focus, &:active {
                    color: var(--primary_color);
                    transition: color 200ms linear;
                }
            }
        }

        .loadingMessage {
            padding: 20px;
            .rems(12);
            line-height: 1.2em;
            font-weight: 600;
            text-align: center;
            position: relative;

            .loadingSpinner {
                height: 40px;

                .innerSpinner {
                    transform: translateZ(0) scale(0.5);
                    position: relative;
                    left: 20px;
                }
            }
        }

        .editableOption {

            padding: 12px 0;
            text-align: left !important;


            .row {
                float: none;
                clear: both;
                margin: 0;

            }

            & > .row {
                & > label {
                    &:before {

                        @media @mobile {
                            top: 7.5px !important;
                        }
                    }
                }
            }


        }

        .surgerySelected {
            label {
                float: left !important;
                clear: both !important;
                display: block !important;
                .rems(15) !important;
                line-height: 21px !important;
            }
        }

        .surgerySelected {
            float: none;
            clear: both;
            position: relative;
            width: 100%;
        }

        .surgeryBox {

            border: 1px solid var(--primary_color);
            border-radius: 5px;
            padding: 20px;
            position: relative;

            &:not(.surgeryAddressFields) {
                padding-right: 56px;
            }

            &.surgeryAddressFields {
                border-color: var(--border_color_dark);
            }

            & > h4 {
                .rems(16);
                line-height: 1.2em;
                margin: 0 0 20px;
            }

            .surgeryText {

                .rems(12);
                line-height: 1.2em;
                padding: 0 0 8px;
                display: flex;

                &:last-of-type {
                    padding: 0;
                }

                .textLabel {
                    font-weight: 600;
                    flex: 0 0 104px;
                }

                .textValue {
                    font-weight: normal;
                    flex: 1 1 100%;
                }

            }

            .buttonActions {
                padding: 24px 0 0;
            }

            .closeButton {
                position: absolute;
                top: 5px;
                right: 5px;
                width: 48px;
                height: 48px;
                background: transparent;
                color: color-mix(in srgb, var(--fade_mixin_color), var(--text_color) 50%);
                display: flex;
                align-items: center;
                justify-content: center;
                cursor: pointer;
                transition: color 200ms linear;

                &:hover, &:focus, &:active {
                    color: transparent;
                    transition: color 200ms linear;
                }

                svg {
                    width: 16px;
                    height: 16px;
                }
            }

            .row {

                display: flex;
                margin: 0 0 12px 0;

                .inputWrap {
                    display: flex;
                    align-items: center;
                    gap: 16px;

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

                    label {
                        flex: 0 0 108px;
                        .rems(14);
                        line-height: 1.2em;

                        @media @flyout {
                            flex: 0 0 100%;
                            margin: 0 0 8px;
                        }
                    }

                    input {
                        flex: 1 1 100%;

                        @media @flyout {
                            flex: 0 0 100%;
                        }
                    }
                }


            }

        }

        .surgeryEmpty {

            padding: 20px;
            border: 1px solid var(--border_color_dark);
            border-radius: 5px;

            & > h4 {
                .rems(16);
                line-height: 1.2em;
                margin: 0;
                font-family: var(--primary_font);
            }
        }

        .errorBox {

            padding: 4px 0;

            .error {
                margin: 0 0 12px;
                padding: 12px 20px !important;
                .rems(14) !important;
                line-height: 1.2em !important;
                border-radius: 6px !important;

                &:last-of-type {
                    margin: 0;
                }
            }

        }
    }


</style>
