<template>
  <q-card
    class="q-pa-md bg-white row shadow-card q-mb-md"
    style="border-radius: 20px;"
    :flat="false"
  >
    <div class="text-center text-text q-mb-sm col-12 font14 fontbold">
      {{ isEditing ? $t('profile.bank_data.edit_account') : $t('profile.bank_data.bank_account_title') }}
    </div>

    <div class="col-12 field-label q-mb-xs">
      {{ $t('profile.bank_data.bank_code') }}
    </div>

    <q-select
      ref="bankSelectRef"
      v-model="form.bank_code"
      behavior="menu"
      class="q-mb-sm col-12"
      dense
      emit-value
      fill-input
      hide-dropdown-icon
      hide-selected
      input-class="text-text"
      input-debounce="0"
      map-options
      menu-anchor="bottom left"
      menu-self="top left"
      options-dense
      use-input
      outlined
      popup-content-class="bank-select-menu"
      :loading="loadingBanks"
      :menu-offset="[0, 4]"
      :options="bankOptions"
      :options-dark="false"
      :placeholder="$t('profile.bank_data.bank_code_placeholder')"
      :popup-content-style="bankPopupStyle"
      @blur="clearInvalidBankInput"
      @filter="filterBanks"
      @input-value="onBankInputValue"
      @popup-show="updateBankSelectWidth"
    >
      <template #append>
        <q-icon color="grey-7" name="mdi-magnify" />
      </template>

      <template #option="scope">
        <q-item v-bind="scope.itemProps">
          <q-item-section
            class="bank-select-menu__code"
            side
          >
            {{ scope.opt.code }}
          </q-item-section>

          <q-item-section class="bank-select-menu__name">
            <q-item-label class="ellipsis">
              {{ scope.opt.name }}
            </q-item-label>
          </q-item-section>
        </q-item>
      </template>

      <template #no-option>
        <q-item>
          <q-item-section class="text-grey">
            {{ $t("http.errors.no_records_found") }}
          </q-item-section>
        </q-item>
      </template>
    </q-select>

    <div class="row q-mb-sm q-my-auto col-12 row items-center">
      <q-radio
        v-model="form.type"
        class="q-mr-lg text-text"
        color="primary"
        keep-color
        val="checking"
        :label="$t('profile.bank_data.checking')"
      />

      <q-radio
        v-model="form.type"
        class="text-text"
        color="primary"
        keep-color
        val="savings"
        :label="$t('profile.bank_data.savings')"
      />
    </div>

    <div class="row col-12 q-col-gutter-sm q-mb-sm">
      <div class="col-8">
        <div class="field-label q-mb-xs">
          {{ $t('profile.bank_data.agency') }}
        </div>

        <q-input
          v-model="form.branch_number"
          dense
          input-class="text-text"
          inputmode="numeric"
          maxlength="4"
          outlined
          :placeholder="$t('profile.bank_data.agency_placeholder')"
        />
      </div>

      <div class="col-4">
        <div class="field-label q-mb-xs">
          {{ $t('profile.bank_data.agency_digit') }}
        </div>

        <q-input
          v-model="form.branch_check_digit"
          dense
          input-class="text-text"
          maxlength="2"
          outlined
          :placeholder="$t('profile.bank_data.digit_placeholder')"
        />
      </div>
    </div>

    <div class="row col-12 q-col-gutter-sm q-mb-sm">
      <div class="col-8">
        <div class="field-label q-mb-xs">
          {{ $t('profile.bank_data.account') }}
        </div>

        <q-input
          v-model="form.account_number"
          dense
          input-class="text-text"
          inputmode="numeric"
          maxlength="13"
          outlined
          :placeholder="$t('profile.bank_data.account_placeholder')"
        />
      </div>

      <div class="col-4">
        <div class="field-label q-mb-xs">
          {{ $t('profile.bank_data.account_digit') }}
        </div>

        <q-input
          v-model="form.account_check_digit"
          dense
          input-class="text-text"
          maxlength="2"
          outlined
          :placeholder="$t('profile.bank_data.digit_placeholder')"
        />
      </div>
    </div>

    <q-checkbox
      v-if="canBecomePrimary"
      v-model="form.is_primary"
      class="col-12 q-mt-sm text-text font12"
      color="primary"
      dense
      keep-color
      :label="$t('profile.bank_data.set_as_primary')"
    />

    <q-btn
      class="full-width q-mt-lg"
      color="primary"
      no-caps
      padding="8px 16px"
      rounded
      unelevated
      :disable="!canSave"
      :label="isEditing ? $t('profile.bank_data.att_bank') : $t('profile.bank_data.save_account')"
      :loading="saving"
      @click="save"
    />

    <q-btn
      class="full-width q-mt-sm"
      color="grey-7"
      flat
      no-caps
      padding="4px 16px"
      rounded
      :disable="saving"
      :label="$t('profile.bank_data.cancel')"
      @click="$emit('cancel')"
    />
  </q-card>
</template>

<script setup>
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
import { createProviderBankAccount, updateProviderBankAccount } from 'src/api/providerBankAccount';
import { getBanks } from 'src/api/banks';
import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n';

const props = defineProps({
  account: {
    type: Object,
    default: null,
  },
});

const emit = defineEmits(['saved', 'cancel']);

const { t } = useI18n();
const $q = useQuasar();

const banks = ref([]);
const bankOptions = ref([]);
const bankSelectRef = ref(null);
const bankSelectWidth = ref(null);
const loadingBanks = ref(false);
const saving = ref(false);

const isEditing = computed(() => !!props.account?.id);

const form = reactive({
  bank_code: '',
  type: 'checking',
  branch_number: '',
  branch_check_digit: '',
  account_number: '',
  account_check_digit: '',
  is_primary: false,
});

const canBecomePrimary = computed(() => isEditing.value && !props.account?.is_primary);

const bankPopupStyle = computed(() => ({
  maxHeight: '188px',
  overflowY: 'auto',
  width: bankSelectWidth.value ? `${bankSelectWidth.value}px` : undefined,
  maxWidth: bankSelectWidth.value ? `${bankSelectWidth.value}px` : undefined,
}));

const isSelectedBankValid = (code) => {
  if (!code) {
    return false;
  }

  return banks.value.some((bank) => getBankCode(bank) === code);
};

const canSave = computed(
  () =>
    isSelectedBankValid(form.bank_code) &&
    !!form.branch_number &&
    !!form.account_number &&
    !!form.account_check_digit,
);

const getBankCode = (bank) => {
  const code = bank?.code ?? bank?.bank_code ?? bank?.number ?? bank?.value ?? '';
  return String(code).padStart(3, '0');
};

const getBankName = (bank) => bank?.name ?? bank?.label ?? bank?.title ?? '';

const getBankList = (response) => {
  if (Array.isArray(response)) {
    return response;
  }

  if (Array.isArray(response?.data)) {
    return response.data;
  }

  if (Array.isArray(response?.payload)) {
    return response.payload;
  }

  if (response && typeof response === 'object') {
    return Object.entries(response).map(([code, name]) => ({
      code,
      name,
    }));
  }

  return [];
};

const filterBanks = (val, update) => {
  update(() => {
    const needle = normalizeText(val).trim();

    if (!needle) {
      setBankOptions(banks.value);
      return;
    }

    const filtered = banks.value.filter((bank) => {
      const code = getBankCode(bank);
      const name = normalizeText(getBankName(bank));

      return code.includes(needle) || name.includes(needle);
    });

    setBankOptions(filtered);
  });
};

const formatBankOption = (bank) => {
  const code = getBankCode(bank);
  const name = getBankName(bank);

  return {
    code,
    name,
    label: [code, name].filter(Boolean).join(' '),
    value: code,
  };
};

const bankLabel = (code) => {
  const bank = banks.value.find((item) => getBankCode(item) === code);

  return bank ? [getBankCode(bank), getBankName(bank)].filter(Boolean).join(' ') : '';
};

const showSelectedBankLabel = () => {
  bankSelectRef.value?.updateInputValue(bankLabel(form.bank_code), true);
};

const normalizeText = (text) =>
  String(text ?? '')
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .toLowerCase();

const setBankOptions = (list) => {
  bankOptions.value = list.map(formatBankOption).filter((bank) => bank.code);
};

const updateBankSelectWidth = async () => {
  await nextTick();

  bankSelectWidth.value = bankSelectRef.value?.$el?.getBoundingClientRect()?.width ?? null;
};

const clearInvalidBankInput = () => {
  if (!isSelectedBankValid(form.bank_code)) {
    form.bank_code = '';

    bankSelectRef.value?.updateInputValue('', true);

    return;
  }

  showSelectedBankLabel();
};

const onBankInputValue = (value) => {
  const typed = String(value ?? '');

  if (typed !== form.bank_code && typed !== bankLabel(form.bank_code)) {
    form.bank_code = '';
  }
};

const fillForm = (account) => {
  form.bank_code = account?.bank_code ? String(account.bank_code).padStart(3, '0') : '';
  form.type = account?.type || 'checking';
  form.branch_number = account?.branch_number || '';
  form.branch_check_digit = account?.branch_check_digit || '';
  form.account_number = account?.account_number || '';
  form.account_check_digit = account?.account_check_digit || '';
  form.is_primary = false;
};

watch(() => props.account, async (account) => {
  fillForm(account);

  await nextTick();

  showSelectedBankLabel();
});


const save = async () => {
  if (!canSave.value) {
    $q.notify({ type: 'negative', message: t('profile.bank_data.bank_fields_required') });

    return;
  }

  saving.value = true;

  try {
    const payload = {
      bank_code: form.bank_code,
      type: form.type,
      branch_number: form.branch_number,
      branch_check_digit: form.branch_check_digit || null,
      account_number: form.account_number,
      account_check_digit: form.account_check_digit,
    };

    if (canBecomePrimary.value && form.is_primary) {
      payload.is_primary = true;
    }

    const account = isEditing.value
      ? await updateProviderBankAccount(props.account.id, payload)
      : await createProviderBankAccount(payload);

    emit('saved', account);
  } catch (error) {
    console.log(error);
  } finally {
    saving.value = false;
  }
};

const loadBanks = async () => {
  loadingBanks.value = true;

  try {
    const response = await getBanks();

    banks.value = getBankList(response);

    setBankOptions(banks.value);
  } catch (error) {
    console.log(error);
  } finally {
    loadingBanks.value = false;
  }
};

onMounted(async () => {
  fillForm(props.account);

  await loadBanks();

  if (form.bank_code) {
    await nextTick();

    showSelectedBankLabel();
  }

  await updateBankSelectWidth();

  window.addEventListener('resize', updateBankSelectWidth);
});

onBeforeUnmount(() => {
  window.removeEventListener('resize', updateBankSelectWidth);
});
</script>

<style scoped>
.field-label {
  color: #8C8C8C;
  font-size: 12px;
  line-height: 1.2;
}
</style>

<style>
.bank-select-menu {
  background: #FFFFFF !important;
  color: #1F1F1F !important;
  border: 1px solid #E7E7E7;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.14);
  max-height: 188px !important;
  overflow-y: auto !important;
}

.bank-select-menu .q-item {
  min-height: 32px;
  padding: 6px 10px;
  color: #1F1F1F;
}

.bank-select-menu__name {
  min-width: 0;
}

.bank-select-menu__code {
  min-width: 36px;
  color: #8C8C8C;
  font-family: monospace;
  padding-right: 8px;
}
</style>
