<script setup lang="ts">
import { onMounted, watch, reactive, ref, computed } from 'vue';
import useAddressStore, {
  District,
  Province,
  SubDistrict,
} from 'stores/address';
import { selectFilterOptionRefMod } from 'stores/utils';
import { QSelect } from 'quasar';
import { useI18n } from 'vue-i18n';

defineProps<{
  title?: string;
  addressTitle?: string;
  addressTitleEN?: string;
  dense?: boolean;
  outlined?: boolean;
  readonly?: boolean;
  separator?: boolean;
  employee?: boolean;
  disabledRule?: boolean;
  indexId?: number;
  prefixId: string;
  hideTitle?: boolean;
  hideInputEn?: boolean;
  hideIcon?: boolean;

  useEmployment?: boolean;
  useWorkPlace?: boolean;
}>();

const adrressStore = useAddressStore();
const workplace = defineModel<string>('workplace', { default: '' });
const workplaceEN = defineModel<string>('workplaceEn', { default: '' });
const address = defineModel('address', { default: '' });
const addressEN = defineModel('addressEN', { default: '' });
const street = defineModel('street', { default: '' });
const streetEN = defineModel('streetEN', { default: '' });
const moo = defineModel('moo', { default: '' });
const mooEN = defineModel('mooEN', { default: '' });
const soi = defineModel('soi', { default: '' });
const soiEN = defineModel('soiEN', { default: '' });
const provinceId = defineModel<string | null | undefined>('provinceId');
const districtId = defineModel<string | null | undefined>('districtId');
const subDistrictId = defineModel<string | null | undefined>('subDistrictId');
const zipCode = defineModel<string | null | undefined>('zipCode');
const sameWithEmployer = defineModel<boolean>('sameWithEmployer');

const homeCode = defineModel<string | null | undefined>('homeCode');
const employmentOffice = defineModel<string | null | undefined>(
  'employmentOffice',
);
const employmentOfficeEN = defineModel<string | null | undefined>(
  'employmentOfficeEN',
);

const addrOptions = reactive<{
  provinceOps: Province[];
  districtOps: District[];
  subDistrictOps: SubDistrict[];
}>({
  provinceOps: [],
  districtOps: [],
  subDistrictOps: [],
});

const { t } = useI18n();

const fullAddress = computed(() => {
  const addressParts = [address.value];
  const province = provinceOptions.value.find((v) => v.id === provinceId.value);
  const district = districtOptions.value.find((v) => v.id === districtId.value);
  const sDistrict = subDistrictOptions.value.find(
    (v) => v.id === subDistrictId.value,
  );

  if (moo.value) addressParts.push(`${t('form.moo')} ${moo.value}`);
  if (soi.value) addressParts.push(`${t('form.soi')} ${soi.value}`);
  if (street.value) addressParts.push(`${t('form.street')} ${street.value}`);

  if (subDistrictId.value && sDistrict) {
    addressParts.push(typeof sDistrict.name === 'string' ? sDistrict.name : '');
  }

  if (districtId.value && district)
    addressParts.push(typeof district.name === 'string' ? district.name : '');

  if (provinceId.value && province) {
    addressParts.push(
      typeof province.name === 'string' ? `${province.name}` : '',
    );
    sDistrict &&
      addressParts.push(
        typeof sDistrict.zipCode === 'string' ? `${sDistrict.zipCode}` : '',
      );
  }

  return addressParts.join(' ');
});

const fullAddressEN = computed(() => {
  const addressParts = [addressEN.value];
  const province = provinceOptions.value.find((v) => v.id === provinceId.value);
  const district = districtOptions.value.find((v) => v.id === districtId.value);
  const sDistrict = subDistrictOptions.value.find(
    (v) => v.id === subDistrictId.value,
  );

  if (mooEN.value) addressParts.push(`Moo ${mooEN.value}`);
  if (soiEN.value) addressParts.push(`Soi ${soiEN.value}`);
  if (streetEN.value) addressParts.push(`${streetEN.value} Street`);

  if (subDistrictId.value && sDistrict) {
    addressParts.push(
      typeof sDistrict.nameEN === 'string' ? sDistrict.nameEN : '',
    );
  }

  if (districtId.value && district)
    addressParts.push(
      typeof district.nameEN === 'string' ? district.nameEN : '',
    );

  if (provinceId.value && province) {
    addressParts.push(
      typeof province.nameEN === 'string' ? `${province.nameEN}` : '',
    );
    sDistrict &&
      addressParts.push(
        typeof sDistrict.zipCode === 'string' ? `${sDistrict.zipCode}` : '',
      );
  }

  return addressParts.join(' ');
});

async function fetchProvince() {
  const result = await adrressStore.fetchProvince();

  if (result) addrOptions.provinceOps = result;

  provinceFilter = selectFilterOptionRefMod(
    ref(addrOptions.provinceOps),
    provinceOptions,
    'name',
  );

  provinceEnFilter = selectFilterOptionRefMod(
    ref(addrOptions.provinceOps),
    provinceOptions,
    'nameEN',
  );
}

async function fetchDistrict() {
  if (!provinceId.value) return;

  const result = await adrressStore.fetchDistrictByProvinceId(provinceId.value);
  if (result) addrOptions.districtOps = result;

  districtFilter = selectFilterOptionRefMod(
    ref(addrOptions.districtOps),
    districtOptions,
    'name',
  );

  districtEnFilter = selectFilterOptionRefMod(
    ref(addrOptions.districtOps),
    districtOptions,
    'nameEN',
  );
}

async function fetchSubDistrict() {
  if (!districtId.value) return;
  const result = await adrressStore.fetchSubDistrictByProvinceId(
    districtId.value,
  );
  if (result) addrOptions.subDistrictOps = result;

  subDistrictFilter = selectFilterOptionRefMod(
    ref(addrOptions.subDistrictOps),
    subDistrictOptions,
    'name',
  );

  subDistrictEnFilter = selectFilterOptionRefMod(
    ref(addrOptions.subDistrictOps),
    subDistrictOptions,
    'nameEN',
  );
}

async function selectSubDistrict(id: string) {
  if (!id) return;
  zipCode.value =
    addrOptions.subDistrictOps
      ?.filter((x) => x.id === id)
      .map((x) => x.zipCode)[0] ?? '';
}

const provinceOptions = ref<Record<string, unknown>[]>([]);
let provinceFilter: (
  value: string,
  update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;
let provinceEnFilter: (
  value: string,
  update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;

const districtOptions = ref<Record<string, unknown>[]>([]);
let districtFilter: (
  value: string,
  update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;
let districtEnFilter: (
  value: string,
  update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;

const subDistrictOptions = ref<Record<string, unknown>[]>([]);
let subDistrictFilter: (
  value: string,
  update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;
let subDistrictEnFilter: (
  value: string,
  update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;

onMounted(async () => {
  await fetchProvince();
  await fetchDistrict();
  await fetchSubDistrict();
});

watch(provinceId, fetchDistrict);
watch(districtId, fetchSubDistrict);
</script>
<template>
  <div class="col-12">
    <div
      v-if="!hideTitle"
      class="col-12 q-pb-sm text-weight-bold text-body1 row items-center"
    >
      <q-icon
        size="xs"
        class="q-pa-sm rounded q-mr-xs"
        color="info"
        name="mdi-map-marker-radius-outline"
        style="background-color: var(--surface-3)"
      />

      {{ (title && $t(title)) || $t('form.field.address') }}

      <div
        v-if="employee"
        class="surface-3 q-px-sm q-py-xs row text-caption q-ml-md app-text-muted"
        style="border-radius: var(--radius-3)"
      >
        <span
          :id="`${prefixId}-same`"
          class="q-px-sm q-mr-lg rounded cursor-pointer"
          :class="{
            dark: $q.dark.isActive,
            'active-addr': sameWithEmployer,
            'cursor-not-allowed': readonly,
          }"
          @click="readonly ? '' : (sameWithEmployer = true)"
        >
          {{ $t('customerEmployee.form.addressSame') }}
        </span>
        <span
          :id="`${prefixId}-custom`"
          class="q-px-sm rounded cursor-pointer"
          :class="{
            dark: $q.dark.isActive,
            'active-addr': !sameWithEmployer,
            'cursor-not-allowed': readonly,
          }"
          @click="readonly ? '' : (sameWithEmployer = false)"
        >
          {{ $t('customerEmployee.form.addressCustom') }}
        </span>
      </div>
    </div>

    <div class="col-12 row q-col-gutter-y-md">
      <div v-if="useEmployment" class="col-12 row q-col-gutter-sm">
        <q-input
          outlined
          hide-bottom-space
          class="col-3"
          v-model="homeCode"
          mask="###########"
          :dense="dense"
          :label="$t('customer.form.homeCode')"
          :readonly="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `input-address-${indexId}` : 'input-address'}`"
          :rules="
            disabledRule
              ? []
              : [(val) => (val && val.length > 0) || $t('form.error.required')]
          "
        />
        <q-input
          outlined
          hide-bottom-space
          class="col"
          v-model="employmentOffice"
          :dense="dense"
          :label="$t('customer.form.employmentOffice')"
          :readonly="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `input-address-${indexId}` : 'input-address'}`"
        />
        <q-input
          outlined
          hide-bottom-space
          class="col"
          v-model="employmentOfficeEN"
          :dense="dense"
          :label="`${$t('customer.form.employmentOffice')} (EN)`"
          :readonly="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `input-address-${indexId}` : 'input-address'}`"
        />
      </div>

      <template v-if="!hideIcon">
        <div class="col-12 app-text-muted-2">
          <q-icon size="xs" class="q-mr-xs" name="mdi-map-marker-outline" />
          {{ addressTitle || $t('form.address') }}
        </div>
      </template>
      <div class="col-12 row q-col-gutter-sm">
        <div class="row col-12" v-if="useWorkPlace">
          <q-input
            outlined
            hide-bottom-space
            class="col-6"
            v-model="workplace"
            :dense="dense"
            :label="$t('customer.form.workplace')"
            :readonly="readonly || sameWithEmployer"
            :for="`${prefixId}-${indexId !== undefined ? `input-address-${indexId}` : 'input-address'}`"
            :rules="
              disabledRule
                ? []
                : [
                    (val) =>
                      (val && val.length > 0) || $t('form.error.required'),
                  ]
            "
          />
        </div>

        <q-input
          outlined
          hide-bottom-space
          class="col-md-5 col-8"
          v-model="address"
          :dense="dense"
          :label="$t('form.addressNo')"
          :readonly="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `input-address-no-${indexId}` : 'input-address-no'}`"
          :rules="
            disabledRule
              ? []
              : [(val) => (val && val.length > 0) || $t('form.error.required')]
          "
        />
        <q-input
          outlined
          hide-bottom-space
          class="col-md-1 col-4"
          :model-value="readonly ? moo || '-' : moo"
          :dense="dense"
          :label="$t('form.moo')"
          :readonly="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `input-moo-${indexId}` : 'input-moo'}`"
          @update:model-value="(v) => (typeof v === 'string' ? (moo = v) : '')"
        />
        <q-input
          outlined
          hide-bottom-space
          class="col-md-3 col-6"
          :model-value="readonly ? soi || '-' : soi"
          :dense="dense"
          :label="$t('form.soi')"
          :readonly="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `input-soi-${indexId}` : 'input-soi'}`"
          @update:model-value="(v) => (typeof v === 'string' ? (soi = v) : '')"
        />
        <q-input
          outlined
          hide-bottom-space
          class="col-md-3 col-6"
          :model-value="readonly ? street || '-' : street"
          :dense="dense"
          :label="$t('form.street')"
          :readonly="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `input-street-${indexId}` : 'input-street'}`"
          @update:model-value="
            (v) => (typeof v === 'string' ? (street = v) : '')
          "
        />
        <q-select
          autocomplete="off"
          outlined
          clearable
          use-input
          fill-input
          emit-value
          map-options
          hide-selected
          hide-bottom-space
          option-value="id"
          input-debounce="0"
          option-label="name"
          v-model="provinceId"
          class="col-md-3 col-6"
          :dense="dense"
          :label="$t('form.province')"
          :options="provinceOptions"
          :readonly="readonly || sameWithEmployer"
          :hide-dropdown-icon="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `select-province-${indexId}` : 'select-province'}`"
          :rules="
            disabledRule
              ? []
              : [
                  (val) =>
                    (val && val.length > 0) ||
                    $t('form.error.selectField', {
                      field: $t('form.province'),
                    }),
                ]
          "
          @filter="provinceFilter"
          @update:model-value="districtId = subDistrictId = zipCode = null"
        >
          <template v-slot:no-option>
            <q-item>
              <q-item-section class="text-grey">
                {{ $t('general.noData') }}
              </q-item-section>
            </q-item>
          </template>
        </q-select>

        <q-select
          autocomplete="off"
          outlined
          clearable
          use-input
          fill-input
          emit-value
          map-options
          hide-selected
          hide-bottom-space
          option-value="id"
          input-debounce="0"
          option-label="name"
          v-model="districtId"
          class="col-md-3 col-6"
          :dense="dense"
          :label="$t('form.district')"
          :options="districtOptions"
          :readonly="readonly || sameWithEmployer"
          :hide-dropdown-icon="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `select-district-${indexId}` : 'select-district'}`"
          :rules="
            disabledRule
              ? []
              : [
                  (val) =>
                    (val && val.length > 0) ||
                    $t('form.error.selectField', {
                      field: $t('form.district'),
                    }),
                ]
          "
          @filter="districtFilter"
          @update:model-value="subDistrictId = zipCode = null"
        >
          <template v-slot:no-option>
            <q-item>
              <q-item-section class="text-grey">
                {{ $t('general.noData') }}
              </q-item-section>
            </q-item>
          </template>
        </q-select>
        <q-select
          autocomplete="off"
          outlined
          clearable
          use-input
          fill-input
          emit-value
          map-options
          hide-selected
          hide-bottom-space
          option-value="id"
          input-debounce="0"
          option-label="name"
          class="col-md-3 col-6"
          v-model="subDistrictId"
          :dense="dense"
          :label="$t('form.subDistrict')"
          :options="subDistrictOptions"
          :readonly="readonly || sameWithEmployer"
          :hide-dropdown-icon="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `select-sub-district-${indexId}` : 'select-sub-district'}`"
          :rules="
            disabledRule
              ? []
              : [
                  (val) =>
                    (val && val.length > 0) ||
                    $t('form.error.selectField', {
                      field: $t('form.subDistrict'),
                    }),
                ]
          "
          @update:model-value="(v: string) => selectSubDistrict(v)"
          @filter="subDistrictFilter"
        >
          <template v-slot:no-option>
            <q-item>
              <q-item-section class="text-grey">
                {{ $t('general.noData') }}
              </q-item-section>
            </q-item>
          </template>
        </q-select>
        <q-input
          :for="`${prefixId}-${indexId !== undefined ? `input-zip-code-${indexId}` : 'input-zip-code'}`"
          :dense="dense"
          outlined
          :disable="!readonly && !sameWithEmployer"
          readonly
          :label="$t('form.zipCode')"
          class="col-md-3 col-6"
          :model-value="
            addrOptions.subDistrictOps
              ?.filter((x) => x.id === subDistrictId)
              .map((x) => x.zipCode)[0] ?? ''
          "
        />
        <q-input
          outlined
          hide-bottom-space
          class="col-12"
          :model-value="address ? fullAddress : ''"
          :dense="dense"
          :label="$t('form.fullAddress')"
          readonly
          :disable="!readonly && !sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `input-full-address-${indexId}` : 'input-full-address'}`"
        />
      </div>
      <template v-if="!hideIcon">
        <div class="col-12 app-text-muted-2" v-if="!hideInputEn">
          <q-icon size="xs" class="q-mr-xs" name="mdi-map-marker-outline" />
          {{ addressTitleEN || $t('form.address', { suffix: '(EN)' }) }}
        </div>
      </template>
      <div class="col-12 row q-col-gutter-sm" v-if="!hideInputEn">
        <div class="row col-12" v-if="useWorkPlace">
          <q-input
            outlined
            hide-bottom-space
            class="col-6"
            v-model="workplaceEN"
            :dense="dense"
            :label="$t('customer.form.workplaceEN')"
            :readonly="readonly || sameWithEmployer"
            :for="`${prefixId}-${indexId !== undefined ? `input-address-${indexId}` : 'input-address'}`"
            :rules="
              disabledRule
                ? []
                : [
                    (val) =>
                      (val && val.length > 0) || $t('form.error.required'),
                  ]
            "
          />
        </div>

        <q-input
          :for="`${prefixId}-${indexId !== undefined ? `input-address-en-${indexId}` : 'input-address-en'}`"
          :dense="dense"
          :readonly="readonly || sameWithEmployer"
          outlined
          hide-bottom-space
          label="Address No."
          class="col-md-5 col-8"
          v-model="addressEN"
          :rules="
            disabledRule
              ? []
              : [(val) => (val && val.length > 0) || $t('form.error.required')]
          "
        />
        <q-input
          outlined
          hide-bottom-space
          class="col-md-1 col-4"
          :model-value="readonly ? mooEN || '-' : mooEN"
          :dense="dense"
          label="Moo"
          :readonly="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `input-moo-${indexId}` : 'input-moo'}`"
          @update:model-value="
            (v) => (typeof v === 'string' ? (mooEN = v) : '')
          "
        />
        <q-input
          outlined
          hide-bottom-space
          class="col-md-3 col-6"
          :model-value="readonly ? soiEN || '-' : soiEN"
          :dense="dense"
          label="Soi"
          :readonly="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `input-soi-${indexId}` : 'input-soi'}`"
          @update:model-value="
            (v) => (typeof v === 'string' ? (soiEN = v) : '')
          "
        />
        <q-input
          outlined
          hide-bottom-space
          class="col-md-3 col-6"
          :model-value="readonly ? streetEN || '-' : streetEN"
          :dense="dense"
          label="Street"
          :readonly="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `input-street-${indexId}` : 'input-street'}`"
          @update:model-value="
            (v) => (typeof v === 'string' ? (streetEN = v) : '')
          "
        />
        <q-select
          autocomplete="off"
          outlined
          clearable
          use-input
          fill-input
          emit-value
          map-options
          hide-selected
          hide-bottom-space
          option-value="id"
          input-debounce="0"
          v-model="provinceId"
          option-label="nameEN"
          class="col-md-3 col-6"
          :dense="dense"
          label="Province"
          :options="provinceOptions"
          :readonly="readonly || sameWithEmployer"
          :hide-dropdown-icon="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `select-province-en-${indexId}` : 'select-province-en'}`"
          :rules="
            disabledRule
              ? []
              : [
                  (val) =>
                    (val && val.length > 0) ||
                    $t('form.error.selectField', {
                      field: $t('form.province'),
                    }),
                ]
          "
          @update:model-value="districtId = subDistrictId = zipCode = null"
          @filter="provinceEnFilter"
        >
          <template v-slot:no-option>
            <q-item>
              <q-item-section class="text-grey">
                {{ $t('general.noData') }}
              </q-item-section>
            </q-item>
          </template>
        </q-select>
        <q-select
          autocomplete="off"
          outlined
          clearable
          use-input
          fill-input
          emit-value
          map-options
          hide-selected
          hide-bottom-space
          option-value="id"
          input-debounce="0"
          v-model="districtId"
          option-label="nameEN"
          class="col-md-3 col-6"
          :dense="dense"
          label="District"
          :options="districtOptions"
          :readonly="readonly || sameWithEmployer"
          :hide-dropdown-icon="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `select-district-en-${indexId}` : 'select-district-en'}`"
          :rules="
            disabledRule
              ? []
              : [
                  (val) =>
                    (val && val.length > 0) ||
                    $t('form.error.selectField', {
                      field: $t('form.district'),
                    }),
                ]
          "
          @update:model-value="subDistrictId = zipCode = null"
          @filter="districtEnFilter"
        >
          <template v-slot:no-option>
            <q-item>
              <q-item-section class="text-grey">
                {{ $t('general.noData') }}
              </q-item-section>
            </q-item>
          </template>
        </q-select>
        <q-select
          autocomplete="off"
          outlined
          clearable
          use-input
          fill-input
          emit-value
          map-options
          hide-selected
          hide-bottom-space
          option-value="id"
          input-debounce="0"
          option-label="nameEN"
          class="col-md-3 col-6"
          v-model="subDistrictId"
          :dense="dense"
          label="Sub-District"
          :options="subDistrictOptions"
          :readonly="readonly || sameWithEmployer"
          :hide-dropdown-icon="readonly || sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `select-sub-district-en-${indexId}` : 'select-sub-district-en'}`"
          :rules="
            disabledRule
              ? []
              : [
                  (val) =>
                    (val && val.length > 0) ||
                    $t('form.error.selectField', {
                      field: $t('form.subDistrict'),
                    }),
                ]
          "
          @update:model-value="(v: string) => selectSubDistrict(v)"
          @filter="subDistrictEnFilter"
        >
          <template v-slot:no-option>
            <q-item>
              <q-item-section class="text-grey">
                {{ $t('general.noData') }}
              </q-item-section>
            </q-item>
          </template>
        </q-select>
        <q-input
          hide-bottom-space
          :for="`${prefixId}-${indexId !== undefined ? `input-zip-code-${indexId}` : 'input-zip-code'}`"
          :dense="dense"
          outlined
          readonly
          :disable="!readonly && !sameWithEmployer"
          zip="zip-en"
          label="Zip Code"
          class="col-md-3 col-6"
          :model-value="
            addrOptions.subDistrictOps
              ?.filter((x) => x.id === subDistrictId)
              .map((x) => x.zipCode)[0] ?? ''
          "
        />
        <q-input
          outlined
          hide-bottom-space
          class="col-12"
          :model-value="addressEN ? fullAddressEN : ''"
          :dense="dense"
          label="Full Address"
          readonly
          :disable="!readonly && !sameWithEmployer"
          :for="`${prefixId}-${indexId !== undefined ? `input-full-address-en-${indexId}` : 'input-full-address-en'}`"
        />
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.active-addr {
  color: hsl(var(--info-bg));
  background-color: hsla(var(--info-bg) / 0.1);
  border-radius: var(--radius-3);

  &.dark {
    background-color: var(--surface-1);
  }
}
</style>
