<template>
  <div :class="b()">
    <field
      v-model="data.name"
      clearable
      :label="$t('name')"
      :placeholder="$t('namePlaceholder')"
      :error="errorInfo.name"
      @focus="onFocus('name')"
    />
    <field
      v-model="data.tel"
      clearable
      type="tel"
      :label="$t('tel')"
      :placeholder="$t('telPlaceholder')"
      :error="errorInfo.tel"
      @focus="onFocus('tel')"
    />
    <field
      v-show="showArea"
      readonly
      :label="$t('area')"
      :placeholder="$t('areaPlaceholder')"
      :value="areaText"
      @click="showAreaPopup = true"
    />
    <address-edit-detail
      v-show="showDetail"
      :focused="detailFocused"
      :value="data.addressDetail"
      :error="errorInfo.addressDetail"
      :detail-rows="detailRows"
      :search-result="searchResult"
      :show-search-result="showSearchResult"
      @focus="onFocus('addressDetail')"
      @blur="detailFocused = false"
      @input="onChangeDetail"
      @select-search="$emit('select-search', $event)"
    />
    <field
      v-if="showPostal"
      v-show="!hideBottomFields"
      v-model="data.postalCode"
      type="tel"
      maxlength="6"
      :label="$t('postal')"
      :placeholder="$t('postal')"
      :error="errorInfo.postalCode"
      @focus="onFocus('postalCode')"
    />
    <slot />
    <switch-cell
      v-if="showSetDefault"
      v-show="!hideBottomFields"
      v-model="data.isDefault"
      :title="$t('defaultAddress')"
      @change="$emit('change-default', $event)"
    />

    <div
      v-show="!hideBottomFields"
      :class="b('buttons')"
    >
      <van-button
        block
        :loading="isSaving"
        type="danger"
        :text="saveButtonText || $t('save')"
        @click="onSave"
      />
      <van-button
        v-if="showDelete"
        block
        :loading="isDeleting"
        :text="deleteButtonText || $t('delete')"
        @click="onDelete"
      />
    </div>

    <popup
      v-model="showAreaPopup"
      position="bottom"
      :lazy-render="false"
      get-container="body"
    >
      <van-area
        ref="area"
        :loading="!areaListLoaded"
        :value="data.areaCode"
        :area-list="areaList"
        @confirm="onAreaConfirm"
        @cancel="showAreaPopup = false"
      />
    </popup>
  </div>
</template>

<script>
/* eslint-disable camelcase */
import create from '../utils/create';
import { isObj } from '../utils';
import Field from '../field';
import VanButton from '../button';
import Popup from '../popup';
import Toast from '../toast';
import Dialog from '../dialog';
import VanArea from '../area';
import AddressEditDetail from './Detail';
import SwitchCell from '../switch-cell';
import validateMobile from '../utils/validate/mobile';

const defaultData = {
  name: '',
  tel: '',
  country: '',
  province: '',
  city: '',
  county: '',
  areaCode: '',
  postalCode: '',
  addressDetail: '',
  isDefault: false
};

export default create({
  name: 'address-edit',

  components: {
    Field,
    Popup,
    VanArea,
    VanButton,
    SwitchCell,
    AddressEditDetail
  },

  props: {
    areaList: Object,
    isSaving: Boolean,
    isDeleting: Boolean,
    validator: Function,
    showDelete: Boolean,
    showPostal: Boolean,
    searchResult: Array,
    showSetDefault: Boolean,
    showSearchResult: Boolean,
    saveButtonText: String,
    deleteButtonText: String,
    showArea: {
      type: Boolean,
      default: true
    },
    showDetail: {
      type: Boolean,
      default: true
    },
    detailRows: {
      type: Number,
      default: 1
    },
    addressInfo: {
      type: Object,
      default: () => ({ ...defaultData })
    },
    telValidator: {
      type: Function,
      default: validateMobile
    }
  },

  data() {
    return {
      data: {},
      showAreaPopup: false,
      detailFocused: false,
      errorInfo: {
        tel: false,
        name: false,
        postalCode: false,
        addressDetail: false
      }
    };
  },

  computed: {
    // hide bottom field when use search && detail get focused
    hideBottomFields() {
      return this.searchResult.length && this.detailFocused;
    },

    areaListLoaded() {
      return isObj(this.areaList) && Object.keys(this.areaList).length;
    },

    areaText() {
      const { country, province, city, county, areaCode } = this.data;
      if (areaCode) {
        const arr = [country, province, city, county];
        if (province && province === city) {
          arr.splice(1, 1);
        }
        return arr.filter(text => text).join('/');
      }
      return '';
    }
  },

  watch: {
    addressInfo: {
      handler(val) {
        this.data = {
          ...defaultData,
          ...val
        };

        this.setAreaCode(val.areaCode);
      },
      deep: true,
      immediate: true
    },

    areaList() {
      this.setAreaCode(this.data.areaCode);
    }
  },

  methods: {
    onFocus(key) {
      this.errorInfo[key] = false;
      this.detailFocused = key === 'addressDetail';
      this.$emit('focus', key);
    },

    onChangeDetail(val) {
      this.data.addressDetail = val;
      this.$emit('change-detail', val);
    },

    onAreaConfirm(values) {
      this.showAreaPopup = false;
      this.assignAreaValues();
      this.$emit('change-area', values);
    },

    assignAreaValues() {
      const { area } = this.$refs;
      if (area) {
        const detail = area.getArea();
        detail.areaCode = detail.code;
        delete detail.code;
        Object.assign(this.data, detail);
      }
    },

    onSave() {
      const items = ['name', 'tel', 'areaCode', 'addressDetail'];

      if (this.showPostal) {
        items.push('postalCode');
      }

      const isValid = items.every(item => {
        const msg = this.getErrorMessage(item);
        if (msg) {
          this.errorInfo[item] = true;
          Toast(msg);
        }
        return !msg;
      });

      if (isValid && !this.isSaving) {
        this.$emit('save', this.data);
      }
    },

    getErrorMessage(key) {
      const value = String(this.data[key] || '').trim();
      const { $t } = this;

      if (this.validator) {
        const message = this.validator(key, value);
        if (message) {
          return message;
        }
      }

      switch (key) {
        case 'name':
          return value ? '' : $t('nameEmpty');
        case 'tel':
          return this.telValidator(value) ? '' : $t('telInvalid');
        case 'areaCode':
          return value ? '' : $t('areaEmpty');
        case 'addressDetail':
          return value ? '' : $t('addressEmpty');
        case 'postalCode':
          return value && !/^\d{6}$/.test(value) ? $t('postalEmpty') : '';
      }
    },

    onDelete() {
      Dialog.confirm({
        title: this.$t('confirmDelete')
      })
        .then(() => {
          this.$emit('delete', this.data);
        })
        .catch(() => {
          this.$emit('cancel-delete', this.data);
        });
    },

    // get values of area component
    getArea() {
      return this.$refs.area ? this.$refs.area.getValues() : [];
    },

    // set area code to area component
    setAreaCode(code) {
      this.data.areaCode = code || '';

      if (code) {
        this.$nextTick(this.assignAreaValues);
      }
    },

    setAddressDetail(value) {
      this.data.addressDetail = value;
    }
  }
});
</script>
