<template>
  <v-card width="100%" :loading="processing">
    <v-toolbar>
      <v-row no-gutters class="fill-height px-6 d-flex justify-space-between align-center" align="center">
        <span class="font-weight-bold text-h5 text-capitalize">
          {{ prop.mode }} {{ formatVisitorType(type) }}
        </span>
        <ButtonClose @click="emit('close:all')" />
      </v-row>
    </v-toolbar>
    <v-card-text style="max-height: 100vh; overflow-y: auto" class="pa-5 my-3">
      <div class="w-100 d-flex justify-space-between ga-2">
        <span class="text-subtitle-1 w-100 font-weight-bold mb-3">{{
          formTitle
          }}</span>
        <span v-if="withStep2 || withStep3" class="text-subtitle-2 font-weight-bold" style="text-wrap: nowrap">Step
          <span class="text-primary-button">{{ contractorStep }}</span>/{{ withStep3 ? 3 : withStep2 ? 2 : 1 }}</span>
      </div>
      <v-form ref="formRef" v-model="validForm" :disabled="processing" @click="errorMessage = ''">
        <v-row no-gutters class="pt-4">
          <v-col v-if="shouldShowField('contractorType')" cols="12">
            <InputLabel class="text-capitalize" title="Contractor Type" required />
            <v-combobox v-model="contractorTypeObj" v-model:search="contractorTypeInput" ref="contractorTypeCombo"
              autocomplete="off" :hide-no-data="false" @update:focused="handleFocusedContractorType"
              :items="contractorTypes" :rules="[requiredRule]" item-value="value"
              @update:model-value="handleSelectContractorType" variant="outlined" density="comfortable" persistent-hint
              small-chips>
              <template v-slot:no-data>
                <v-list-item>
                  <v-list-item-title @click.stop="handleAddNewContractorType" class="d-flex align-center ga-1">
                    <span><v-icon icon="mdi-plus" /></span> Add "<strong>{{
                      contractorTypeInput
                      }}</strong>" as custom contractor type.
                  </v-list-item-title>
                </v-list-item>
              </template>
            </v-combobox>
          </v-col>

          <v-col v-if="shouldShowField('attachments')" class="w-100">
            <InputLabel class="text-capitalize" title="Attach Image" />
            <InputFileV2 v-model="visitor.attachments" multiple :max-length="3" />
          </v-col>

          <v-col v-if="shouldShowField('name')" cols="12">
            <v-row>
              <v-col cols="12">
                <InputLabel class="text-capitalize" title="Full Name" required />
                <v-text-field v-model.trim="visitor.name" density="comfortable" :rules="[requiredRule]" />
              </v-col>
            </v-row>
          </v-col>

          <v-col v-if="shouldShowField('nric')" cols="12">
            <v-row>
              <v-col cols="12">
                <InputLabel class="text-capitalize" title="NRIC" :required="requireNRIC" />
                <InputNRICNumber v-model="visitor.nric" density="comfortable"
                  :rules="[requireNRIC ? requiredRule : () => true]" :key="currentAutofillSource + 'nric-key'"
                  @update:model-value="handleUpdateNRIC" :loading="fetchPersonByNRICPending" />
              </v-col>
            </v-row>
          </v-col>

          <v-col v-if="shouldShowField('contact')" cols="12">
            <InputLabel class="text-capitalize" title="Phone Number" required />
            <InputPhoneNumberV2 v-model="visitor.contact" :rules="[requiredRule]" density="comfortable"
              :key="currentAutofillSource + 'phone-key'" :loading="fetchPersonByContactPending"
              @update:model-value="handleUpdateContact" />
          </v-col>

          <v-col v-if="shouldShowField('deliveryType')" cols="12">
            <v-row>
              <v-col cols="12">
                <v-radio-group v-model="visitor.deliveryType" inline color="primary" :rules="[requiredRule]">
                  <v-radio label="Food" value="Food"></v-radio>
                  <v-radio label="Parcel" value="Parcel"></v-radio>
                </v-radio-group>
              </v-col>
            </v-row>
          </v-col>

          <template v-if="shouldShowField('company')">
            <v-col cols="12">
              <InputLabel class="text-capitalize" title="Company Name" />
              <v-combobox v-model="visitor.company" v-model:search="companyNameInput" ref="companyCombo"
                autocomplete="off" :hide-no-data="false" :items="companyNames" item-value="value"
                :loading="fetchCompanyListPending" @update:model-value="handleSelectCompanyName" variant="outlined"
                density="comfortable" persistent-hint small-chips>
                <template v-slot:no-data>
                  <v-list-item>
                    <v-list-item-title v-if="fetchCompanyListPending">
                      <v-progress-circular indeterminate size="20" class="mr-3" />
                      Searching companies…
                    </v-list-item-title>
                    <v-list-item-title v-else-if="companyNameInput" @click.stop="handleAddNewCompany"
                      class="d-flex align-center ga-1">
                      <span><v-icon icon="mdi-plus" /></span>Add "<strong>{{ companyNameInput }}</strong>" as new
                      company.
                    </v-list-item-title>
                    <v-list-item-title v-else-if="!companyNameInput && companyNames.length === 0">
                      Start typing to search for companies.
                    </v-list-item-title>
                    <v-list-item-title v-else>
                      No companies available. Start typing to add a new one.
                    </v-list-item-title>
                  </v-list-item>
                </template>
              </v-combobox>
            </v-col>
          </template>

          <template v-if="shouldShowField('delivery-company')">
            <v-col cols="12">
              <InputLabel class="text-capitalize" title="Delivery Company" />
              <v-combobox v-model="deliveryCompany" v-model:search="deliveryCompanyInput" ref="companyCombo"
                autocomplete="off" :hide-no-data="false" :items="deliveryCompanyList" item-value="value"
                :loading="siteDataPending" variant="outlined" density="comfortable" persistent-hint small-chips>
                <template v-slot:no-data>
                  <v-list-item>
                    <v-list-item-title v-if="fetchCompanyListPending">
                      <v-progress-circular indeterminate size="20" class="mr-3" />
                      Searching companies…
                    </v-list-item-title>
                    <v-list-item-title v-else-if="companyNameInput" @click.stop="handleAddNewCompany"
                      class="d-flex align-center ga-1">
                      <span><v-icon icon="mdi-plus" /></span>Add "<strong>{{ companyNameInput }}</strong>" as new
                      company.
                    </v-list-item-title>
                    <v-list-item-title v-else-if="!companyNameInput && companyNames.length === 0">
                      Start typing to search for companies.
                    </v-list-item-title>
                    <v-list-item-title v-else>
                      No companies available. Start typing to add a new one.
                    </v-list-item-title>
                  </v-list-item>
                </template>
              </v-combobox>
            </v-col>
          </template>


          <v-col v-if="shouldShowField('plateNumber')" cols="12">
            <v-row>
              <v-col cols="12">
                <InputLabel class="text-capitalize" title="Vehicle Number" required />
                <!-- <v-text-field v-model.trim.uppercase="visitor.plateNumber" density="comfortable" /> -->
                <InputVehicleNumber v-model="visitor.plateNumber" density="comfortable" />
              </v-col>
            </v-row>
          </v-col>

          <v-col v-if="shouldShowField('block')" cols="12">
            <InputLabel class="text-capitalize" title="Block" required />
            <v-autocomplete v-model="visitor.block" :items="blocksArray" item-value="value" autocomplete="off" item-title="title" :key="blockListDataPending ? 'block-list-pending' : 'block-list-ready'"
              :loading="blockListDataPending" @update:model-value="handleChangeBlock" density="comfortable"
              :rules="[requiredRule]" />
          </v-col>

          <v-col v-if="shouldShowField('level')" cols="12">
            <InputLabel class="text-capitalize" title="Level" required />
            <v-autocomplete v-model="visitor.level" :items="levelsArray"  density="comfortable" autocomplete="off"
              :disabled="!visitor.block" :key="levelListDataPending ? 'level-list-pending' : 'level-list-ready'"  :loading="levelsDataPending" @update:model-value="handleChangeLevel"
              :rules="[requiredRule]" />
          </v-col>
          <v-col v-if="shouldShowField('unit')" cols="12">
            <InputLabel class="text-capitalize" title="Unit" required />
            <v-autocomplete v-model="visitor.unit" :items="unitsArray" density="comfortable" autocomplete="off" item-title="title"
              item-value="value" :disabled="!visitor.level" :key="unitListDataPending ? 'unit-list-pending' : 'unit-list-ready'" :loading="unitsDataPending" :rules="[requiredRule]"
              @update:model-value="handleUpdateUnit" />
          </v-col>

          <v-col v-if="shouldShowField('unit')" cols="12">
            <InputLabel class="text-capitalize" title="Registered Unit Company Name" required
              :key="'unit-key' + visitor.level" />
            <v-text-field v-model.trim="registeredUnitCompanyName" density="comfortable"
              :loading="buildingUnitDataPending" readonly class="no-pointer" />
          </v-col>

          <v-col v-if="shouldShowField('remarks')" cols="12">
            <InputLabel class="text-capitalize" title="Remarks" />
            <v-textarea v-model="visitor.remarks" density="comfortable" :rows="3" no-resize />
          </v-col>

          <v-col v-if="(withStep2 || withStep3) && contractorStep === 2" cols="12">
            <PassInformation v-model:pass="visitor.visitorPass" v-model:keys="visitor.passKeys" :site="prop.site"
              :type="prop.type" :contractor-type="visitor.contractorType" :hide-keys="!showShowKeysField" />
            <EntryPassInformation v-if="entryPassSettings?.data?.settings?.nfcPass" v-model="passType"
              v-model:quantity="passQuantity" v-model:cards="passCards" :settings="entryPassSettings"
              :loading="entryPassSettingsPending" :site-id="prop.site" :unit-id="visitor.unit || null" />
          </v-col>

          <v-col v-if="withStep3 && contractorStep === 3" cols="12">
            <MemberInformation v-model="visitor.members" :type="prop.type" :contractor-type="visitor.contractorType"
              :site="prop.site" :selected-visitor-pass="visitor.visitorPass" />
          </v-col>

          <v-col v-if="prop.mode === 'add'" cols="12" class="mt-2">
            <v-checkbox v-model="createMore" density="comfortable" hide-details>
              <template #label>
                <span class="text-subtitle-2 font-weight-bold">
                  Create more
                </span>
              </template>
            </v-checkbox>
          </v-col>
        </v-row>
      </v-form>
    </v-card-text>

    <v-row no-gutters class="w-100" v-if="errorMessage">
      <p class="text-error w-100 text-center text-subtitle-2">
        {{ errorMessage }}
      </p>
    </v-row>
    <v-toolbar density="compact">
      <v-row no-gutters>
        <v-col cols="6">
          <v-btn v-if="
            prop.mode === 'add' &&
            (withStep2 || withStep3) &&
            contractorStep > 1
          " tile block variant="text" class="text-none" size="48" @click="handleGoToPreviousPage" text="Back" />
          <v-btn v-else-if="prop.mode === 'add' || prop.mode === 'register'" tile block variant="text" class="text-none"
            size="48" @click="backToSelection" text="Back to Selection" />
          <v-btn v-else tile block variant="text" class="text-none" size="48" @click="emit('close:all')" text="Close" />
        </v-col>
        <v-col cols="6">
          <v-btn v-if="showNextButton" tile block variant="flat" color="primary-button" class="text-none" size="48"
            :disabled="processing" @click="handleNextPage" :text="'Next'" />
          <v-btn v-else tile block variant="flat" color="black" class="text-none" size="48"
            :disabled="!validForm || processing || membersFieldIncomplete" @click="submit"
            :text="prop.mode == 'add' ? 'Submit' : 'Update'" />
        </v-col>
      </v-row>
    </v-toolbar>

    <v-dialog v-model="dialog.vehicleNumberUsersList" v-if="vehicleNumberUserItems.length > 0" persistent
      max-width="600">
      <SearchVehicleNumberUser :vehicle-number="visitor.plateNumber ?? ''"
        :vehicle-number-users-list="vehicleNumberUserItems" @close="dialog.vehicleNumberUsersList = false"
        @update:people="handleAutofillDataViaVehicleNumber" />
    </v-dialog>

    <v-dialog v-model="dialog.showNonCheckedOutDialog" max-width="700" persistent>
      <v-card :loading="loading.checkingOut">
        <v-toolbar>
          <v-toolbar-title>
            <v-row no-gutters class="d-flex align-center justify-space-between">
              <span class="font-weight-bold">
                You have an unchecked-out vehicle for: {{ visitor.plateNumber }}
              </span>
            </v-row>
          </v-toolbar-title>
        </v-toolbar>

        <v-card-text>

          <v-list lines="three">
            <v-list-item v-if="matchingPlateNumberNonCheckedOutArr.length > 0"
              v-for="v in matchingPlateNumberNonCheckedOutArr" :key="v._id" class="cursor-pointer">
              <v-list-item-title>
                {{ v.plateNumber }} - {{ v.name }}
              </v-list-item-title>

              <v-list-item-subtitle>
                Checked In at : {{ UTCToLocalTIme(v.checkIn) }}
              </v-list-item-subtitle>

              <template #append>
                <v-btn size="x-small" class="text-capitalize" color="red" text="Checkout"
                  :loading="loading.checkingOut && v?._id === prop.visitorData?._id"
                  @click.stop="handleCheckout(v._id)" />
              </template>

            </v-list-item>
          </v-list>

        </v-card-text>
      </v-card>
    </v-dialog>
  </v-card>
</template>

<script setup lang="ts">
import useBuildingUnit from '../composables/useBuildingUnit';
import useWebUsb from '../composables/useWebUsb';


const prop = defineProps({
  type: {
    type: String as PropType<TVisitorType>,
    required: true,
  },
  org: {
    type: String,
    required: true,
  },
  site: {
    type: String,
    required: true,
  },
  mode: {
    type: String as PropType<"add" | "edit" | "register">,
    default: "add",
  },
  visitorData: {
    type: Object as PropType<Partial<TVisitor> | null>,
    default: null,
  },
});

type AutofillSource = "nric" | "contact" | "vehicleNumber" | null;
const currentAutofillSource = ref<AutofillSource>(null);


const { requiredRule, debounce, UTCToLocalTIme } = useUtils();
const { getSiteById } = useSiteSettings();
const { getBlocksSelection, getLevelsSelection, getUnitSelection } = useBuilding();
const { createVisitor, typeFieldMap, contractorTypes, getVisitors, updateVisitor } = useVisitor();
const { getBySiteId: getEntryPassSettingsBySiteId } = useSiteEntryPassSettings();
const { createVisitorPass, signQr } = useAccessManagement();
const { testConnection } = useWebUsb();
const { findPersonByNRIC, findPersonByContact, searchCompanyList, findUsersByPlateNumber } = usePeople()
const { getById: getUnitDataById } = useBuildingUnit()

const emit = defineEmits([
  "back",
  "select",
  "done",
  "done:more",
  "error",
  "close",
  "close:all"
]);

const visitor = reactive<Partial<TVisitorPayload>>({
  contractorType: "",
  name: "",
  deliveryType: "",
  company: "",
  nric: "",
  contact: "",
  plateNumber: "",
  block: "",
  level: "",
  unit: "",
  unitName: "",
  remarks: "",
  attachments: [],
  members: [],
  visitorPass: [],
  passKeys: []
});

const passType = ref<string | null>(null);
const passQuantity = ref<number | null>(1);
const passCards = ref<{ _id: string; cardNo: string }[]>([]);

const registeredUnitCompanyName = ref('N/A')

const dialog = reactive({
  vehicleNumberUsersList: false,
  showNonCheckedOutDialog: false,
});

const loading = reactive({
  checkingOut: false,
})

const validForm = ref(false);
const formRef = ref<HTMLFormElement | null>(null);
const processing = ref(false);
const message = ref("");
const errorMessage = ref("");
const createMore = ref(false);

const contractorTypeInput = ref("");
const contractorTypeObj = ref<TDefaultOptionObj | null>(null);
const contractorStep = ref(1);

const companyNameInput = ref("");
const companyNameObj = ref<string | null>(null);


const blocksArray = ref<TDefaultOptionObj[]>([]);
const levelsArray = ref<TDefaultOptionObj[]>([]);
const unitsArray = ref<TDefaultOptionObj[]>([]);

const deliveryCompany = ref("");
const deliveryCompanyInput = ref("");
const deliveryCompanyList = ref<string[]>([]);

const matchingPlateNumberNonCheckedOutArr = ref<TVisitor[]>([])


const vehicleNumberUserItems = ref<TPeople[]>([])


const shouldShowField = (fieldKey: keyof TVisitorPayload | 'delivery-company') => {
  if ((!withStep2.value && !withStep3.value) || contractorStep.value === 1) {
    const visibleFields = typeFieldMap[prop.type];
    return visibleFields?.includes(fieldKey);
  }
};

const withStep2 = computed(() => {
  const step2Types = ["guest", "walk-in"];
  return step2Types.includes(prop.type);
})

const withStep3 = computed(() => {
  const step3Types = ["contractor"];
  return step3Types.includes(prop.type);
})

const showNextButton = computed(() => {
  if (withStep3.value) {
    return contractorStep.value === 1 || contractorStep.value === 2
  } else if (withStep2.value) {
    return contractorStep.value === 1
  } else return false
})

const showShowKeysField = computed(() => {
  return prop.type === "contractor"
})

const requireNRIC = computed(() => {
  return prop.type !== 'walk-in' && prop.type !== 'guest';
})

const companyNames = ref<string[]>([])
const companyAutofillDataArray = ref<{ companyName: string[], unit: string, block: number, level: string, unitName: string }[]>([])

const formTitle = computed(() => {
  const isContractorForm = prop.type === "contractor";
  const isDriveInForm = prop.type === "guest";
  const isWalkInForm = prop.type === "walk-in";
  const step = contractorStep.value;
  if ((isContractorForm || isDriveInForm || isWalkInForm) && step === 2) {
    return "Pass & Keys Information";
  } else if (isContractorForm && step === 3) {
    return "Members Information";
  } else return "General Information";
});

function handleSelectContractorType(obj: { title: string; value: string }) {
  visitor.contractorType = obj.value ?? "";
}

function handleFocusedContractorType() {
  // const obj = contractorTypeObj.value;
  // const matched = contractorTypes.some(
  //   (x) => x.value === obj?.value && x.title === obj?.title
  // );
  // if (!matched) {
  //   contractorTypeObj.value = null;
  //   contractorTypeInput.value = ""
  //   visitor.contractorType = "";
  // }
}

const contractorTypeCombo = ref(null)

async function handleAddNewContractorType() {
  visitor.contractorType = contractorTypeInput.value

  const combo = contractorTypeCombo.value as any
  await nextTick();

  combo.isMenuActive = false;
  combo.$el.querySelector("input")?.blur(); ``

}

async function handleSelectCompanyName(company: string) {
  visitor.company = company
  // const selected = companyAutofillDataArray.value.find(x => x.companyName?.includes(company))
  // if (!selected) return

  // visitor.block = selected.block || ""
  // visitor.level = selected.level || ""
  // visitor.unit = selected.unit || ""
  // visitor.unitName = selected.unitName || ""
}

const companyCombo = ref(null)

async function handleAddNewCompany() {
  visitor.company = companyNameInput.value

  const combo = companyCombo.value as any
  await nextTick();

  combo.isMenuActive = false;
  combo.$el.querySelector("input")?.blur();
}


const {
  data: fetchPersonByNRICReq,
  refresh: fetchPersonByNRICRefresh,
  pending: fetchPersonByNRICPending,
} = useLazyAsyncData(`fetch-person`, () => {
  const NRIC = visitor.nric;
  if (!NRIC) return Promise.resolve(null)
  return findPersonByNRIC(NRIC)
}
);

watch(fetchPersonByNRICReq, (obj) => {
  if (obj) {
    currentAutofillSource.value = "nric";
    companyNames.value = obj.companyName ?? []
    visitor.name = obj.name
    visitor.contact = obj.contact
    if (!visitor.company) {
      visitor.company = companyNames.value?.[0]
    }
    visitor.block = obj.block ?? ""
    visitor.level = obj.level ?? ""
    visitor.unit = obj.unit ?? ""

    setTimeout(() => {
      currentAutofillSource.value = null;
    }, 1000);
  }
})

const {
  data: fetchPersonByContactReq,
  refresh: fetchPersonByContactRefresh,
  pending: fetchPersonByContactPending,
} = useLazyAsyncData(`fetch-contact`, () => {
  const contact = visitor.contact;
  if (!contact) return Promise.resolve(null)
  return findPersonByContact(contact)
}
);

watch(fetchPersonByContactReq, (obj: Partial<TPerson>) => {
  if (obj) {
    currentAutofillSource.value = "contact";
    companyNames.value = obj.companyName ?? []
    visitor.name = visitor.name ?? obj.name
    if (!visitor.company) {
      visitor.company = companyNames.value?.[0]
    }
    // visitor.block = visitor.block ?? obj.block ?? ""
    // visitor.level = visitor.level ?? obj.level ?? ""
    // visitor.unit = visitor.unit ?? obj.unit ?? ""
    visitor.nric = visitor.nric ?? obj.nric ?? ""

    setTimeout(() => {
      currentAutofillSource.value = null;
    }, 1000);
  }
})

const {
  data: fetchCompanyListReq,
  refresh: fetchCompanyListRefresh,
  pending: fetchCompanyListPending,

} = useLazyAsyncData(`fetch-company-list`, () => {
  if (!companyNameInput.value) return Promise.resolve(null)
  return searchCompanyList(companyNameInput.value)
})

watch(fetchCompanyListReq, (arr) => {
  if (Array.isArray(arr)) {
    companyAutofillDataArray.value = arr;
    companyNames.value = arr?.flatMap(x => x?.companyName)
  }
})
const {
  data: fetchVisitorListByVehicleNumberReq,
  refresh: fetchVisitorListByVehicleNumberRefresh,
  pending: fetchVisitorListByVehicleNumberPending,

} = useLazyAsyncData(`fetch-visitor-list-by-vehicle-number`, () => {
  if (!visitor.plateNumber) return Promise.resolve(null)
  return getVisitors({ page: 1, limit: 20, site: prop.site, plateNumber: visitor.plateNumber, checkedOut: false, status: "registered" })
})

watch(fetchVisitorListByVehicleNumberReq, (arr: any) => {
  const itemsArray = arr?.items || []
  const isValidArray = Array.isArray(itemsArray)
  matchingPlateNumberNonCheckedOutArr.value = isValidArray ? itemsArray : []
  if (matchingPlateNumberNonCheckedOutArr.value.length > 0) {
    dialog.showNonCheckedOutDialog = true;
  } else {
    dialog.showNonCheckedOutDialog = false;
  }
})


const debounceSearchVisitorsByPlateNumbers = debounce(() => {
  if (!visitor.plateNumber) {
    matchingPlateNumberNonCheckedOutArr.value = []
    dialog.showNonCheckedOutDialog = false;
    return;
  }
  fetchVisitorListByVehicleNumberRefresh();
}, 300);

watch(() => visitor.plateNumber, (newVal) => {
  debounceSearchVisitorsByPlateNumbers();
});



async function handleCheckout(visitorId: string) {
  if (!visitorId) {
    errorMessage.value = "Invalid visitor ID. Cannot proceed with checkout.";
    return;
  }

  try {
    loading.checkingOut = true;
    const res = await updateVisitor(visitorId as string, {
      checkOut: new Date().toISOString(),
    });
    if (res) {
      await fetchVisitorListByVehicleNumberRefresh();

    }
  } catch (error: any) {
    const errorMessage = error?.response?._data?.message;
    console.log("[ERROR]", error);
    errorMessage.value =
      errorMessage || "An error occurred while checking out the vehicle.";
  } finally {
    loading.checkingOut = false;
  }
}




const debounceFetchCompany = debounce(async () => fetchCompanyListRefresh(), 200)

watch(companyNameInput, async (val) => {
  if (!val) {
    companyNames.value = []
    return
  }
  await debounceFetchCompany()
})





function handleAutofillDataViaVehicleNumber(item: TPeople) {

  currentAutofillSource.value = "vehicleNumber";

  visitor.name = item.name
  visitor.nric = item.nric
  visitor.contact = item.contact
  companyNames.value = item.companyName ?? []
  if (!visitor.company) {
    visitor.company = companyNames.value?.[0]
  }
  visitor.block = item.block ?? ""
  visitor.level = item.level ?? ""
  visitor.unit = item.unit ?? ""

  setTimeout(() => {
    currentAutofillSource.value = null;
  }, 1000);
}


const {
  data: entryPassSettings,
  pending: entryPassSettingsPending,
} = useLazyAsyncData(`fetch-entrypass-settings-${prop.site}`, () =>
  getEntryPassSettingsBySiteId(prop.site)
);

const {
  data: siteData,
  refresh: refreshSiteData,
  status: siteStatus,
  pending: siteDataPending,
} = useLazyAsyncData(`visitor-fetch-site-data-${prop.site}`, () =>
  getSiteById(prop.site)
);


const {
  data: blocksListData,
  refresh: refreshBlockListData,
  status: blocksListStatus,
  pending: blockListDataPending,
} = useLazyAsyncData(`visitor-fetch-block-list-data-${prop.site}`, () =>
  getBlocksSelection({ siteId: prop.site }), {watch: [() => prop.site], deep: true }
);



const {
  data: levelsData,
  refresh: refreshLevelsData,
  status: levelsStatus,
  pending: levelsDataPending,
} = useLazyAsyncData(
  `visitor-fetch-levels-data-${prop.site}-${visitor.block}`,
  async () => {
    if (!visitor.block) return Promise.resolve(null);
    // return await getSiteWithLevels(prop.site, { block: Number(visitor.block) });
    return await getLevelsSelection({ siteId: prop.site, blockId: visitor.block });
  }, { watch: [() => visitor.block], deep: true }
);

const {
  data: unitsData,
  refresh: refreshUnitsData,
  status: unitsStatus,
  pending: unitsDataPending,
} = useLazyAsyncData(
  `visitor-fetch-units-data-${prop.site}-${visitor.level}`,
  async () => {
    if (!visitor.level) return Promise.resolve(null);
    return await getUnitSelection({ siteId: prop.site, block: visitor.block, level: visitor.level });
  },{ watch: [() => visitor.level], deep: true }
);


watch(
  siteData,
  (newVal) => {
    const siteDataValue = newVal as TSite;
    if (siteDataValue) {

      deliveryCompanyList.value = Array.isArray(siteDataValue?.deliveryCompanyList) ? siteDataValue.deliveryCompanyList : [];

    } 
  },
  { immediate: true }
);

watch(
  [blocksListData],
  () => {
    if (blocksListStatus.value === 'pending') {
      blocksArray.value = [];
      return;
    }

    const arr = Array.isArray(blocksListData.value?.data) ? blocksListData.value?.data : [];
    blocksArray.value = arr.map((block: any) => ({
      title: block.name,
      value: block._id,
    }));
  },
  { immediate: true, deep: true }
)


watch([levelsData], () => {
  if (levelsStatus.value === 'pending') {
    levelsArray.value = [];
    return;
  }

  const arr = Array.isArray(levelsData.value?.data) ? levelsData.value?.data : [];
  const mappedLevels = arr.map((level: any) => ({
    title: level.name,
    value: level._id,
  }));
  levelsArray.value = mappedLevels;
}, { immediate: true,  deep: true})

watch(
  unitsData,
  (newVal: any) => {
    if (!newVal || !Array.isArray(newVal)) {
      unitsArray.value = []
      return
    }

    const mapped = newVal.map((unit: any) => ({
      title: unit.name,
      value: unit._id,
    }))

    // keep custom unit pushed from autofill
    const selected = visitor.unit
    const exists = mapped.some((u: TDefaultOptionObj) => u.value === selected)

    if (!exists && visitor.unitName) {
      mapped.push({
        title: visitor.unitName,
        value: selected,
      })
    }

    unitsArray.value = mapped
  },
  { immediate: true, deep: true }
)


const { data: buildingUnitData, refresh: refreshBuildingUnitData, pending: buildingUnitDataPending } = useLazyAsyncData(`building-unit-data-${visitor.unit}`, () => {
  if (!visitor.unit) return Promise.resolve(null);
  return getUnitDataById(visitor.unit);
})

// trigger refresh of building unit data when unit changes, to get the latest unit name in case there are changes in the backend
watch(() => visitor.unit, () => {
  if (visitor.unit) {
    refreshBuildingUnitData();
  } else {
    registeredUnitCompanyName.value = 'N/A';
  }
})

watch(buildingUnitData, (newVal: any) => {
  registeredUnitCompanyName.value = newVal?.data?.buildingUnit?.companyName || 'N/A';
})


function handleChangeBlock(value: any) {
  visitor.level = "";
  visitor.unit = "";
}

function handleChangeLevel(value: any) {
  visitor.unit = "";
  visitor.unitName = "";
}

function handleUpdateUnit(value: any) {
  const selectedUnit = unitsArray.value?.find((x: any) => x.value === value);
  visitor.unitName = selectedUnit?.title || "";
}

const debounceFetchNRIC = debounce(fetchPersonByNRICRefresh, 500)
const debounceFetchContact = debounce(fetchPersonByContactRefresh, 500)

function handleUpdateNRIC() {
  if (currentAutofillSource.value && currentAutofillSource.value !== "nric") return;
  debounceFetchNRIC()
}

function handleUpdateContact() {
  if (currentAutofillSource.value && currentAutofillSource.value !== "contact") return;
  debounceFetchContact()
}

function backToSelection() {
  emit("back");
  message.value = "";
}

function handleGoToPreviousPage() {
  if (contractorStep.value > 1) {
    contractorStep.value--;
  }
}

function close() {
  emit("close");
  message.value = "";
}

function formatVisitorType(type: TVisitorType): string {
  switch (type) {
    case "guest":
      return "Drive-In";
    case "contractor":
      return "Contractor";
    case "delivery":
      return "Delivery";
    case "walk-in":
      return "Walk-In";
    case "pick-up":
      return "Pick-Up";
    case "drop-off":
      return "Drop-Off";
    default:
      return "";
  }
}

async function handleNextPage() {
  errorMessage.value = "";
  formRef.value!.validate();
  if (!validForm.value) {
    errorMessage.value = "Please complete all required fields *";
    return;
  }
  const step = contractorStep.value;
  if (step < 3) contractorStep.value++;
  else await submit();
}

async function submit() {
  formRef.value!.validate();
  errorMessage.value = "";
  processing.value = true;

  let payload: Partial<TVisitorPayload> = {
    type: prop.type,
    org: prop.org,
    site: prop.site,
  };

  if (prop.mode === "add" || prop.mode === "register") {
    const allowedFields = typeFieldMap[prop.type];
    for (const key of allowedFields as (keyof TVisitorPayload)[]) {
      if (visitor[key] !== undefined) {
        payload = {
          ...payload,
          [key]: visitor[key],
        };
      }
    }

    const isGuest = prop.type === "guest";
    const isWalkIn = prop.type === "walk-in";
    const isContractor = prop.type === "contractor";
    if (isGuest || isWalkIn || isContractor) {
      payload.visitorPass = visitor.visitorPass;
      payload.passKeys = visitor.passKeys;
    }

  }



  if (prop.type === "contractor") {
    // contractor type logic payload
    payload = {
      ...payload,
      members: visitor.members,
    };
  }

  if (prop.type === "delivery") {
    payload = {
      ...payload,
      company: deliveryCompany.value
    }
  }

  // add register status when registering unregistered visitor
  if (prop.mode === 'register') {
    payload.status = "registered"
  }

  try {
    let res;
    if (prop.mode === "add") {
      res = await createVisitor(payload as TVisitorPayload);
    } else if ((prop.mode === "edit" || prop.mode === "register") && prop.visitorData?._id) {
      const { unitName, ...rest } = payload
      res = await updateVisitor(prop.visitorData._id, rest as TVisitorPayload);
    }

    if (res) {
      if (prop.type === "contractor" && passType.value) {
        const visitorId = res as unknown as string;
        const rawUrl = entryPassSettings.value?.data?.settings?.url;
        const { encrypted: acmUrl } = await $fetch<{ encrypted: string }>(
          `/api/encrypt-acm-url${rawUrl ? `?url=${encodeURIComponent(rawUrl)}` : ""}`
        );
        if (visitorId && acmUrl) {
          const passRes = await createVisitorPass({
            site: prop.site,
            unitId: visitor.unit!,
            quantity: passQuantity.value ?? 1,
            type: passType.value === "QR" ? "QRCODE" : passType.value,
            nfcCards: passCards.value,
            acm_url: acmUrl,
            visitorId,
          });

          if (passType.value === "QR") {
            console.log("[QR Print] passRes:", passRes);
            const accessCards: any[] = (passRes as any)?.data?.accessCards ?? [];
            console.log("[QR Print] accessCards:", accessCards);
            const printer = entryPassSettings.value?.data?.settings?.printer;
            console.log("[QR Print] printer config:", printer);
            if (!printer?.vendorId || !printer?.productId) {
              console.warn("[QR Print] Aborted: no printer configured.");
            } else if (!accessCards.length) {
              console.warn("[QR Print] Aborted: accessCards is empty.");
            } else {
              const vendorId = parseInt(printer.vendorId);
              const productId = parseInt(printer.productId);
              const companyName = visitor.company || "";
              const blockLabel = blocksArray.value.find((b: any) => b.value === visitor.block)?.title || "";
              const levelLabel = levelsArray.value.find((l: any) => l.value === visitor.level)?.title || "";
              const unitLabel = unitsArray.value.find((u: any) => u.value === visitor.unit)?.title || "";
              const address = [blockLabel, levelLabel, unitLabel].filter(Boolean).join("/");
              console.log("[QR Print] Printing", accessCards.length, "card(s). vendorId:", vendorId, "productId:", productId, "address:", address);

              await nextTick();
              for (const qrCode of accessCards) {
                console.log("[QR Print] Signing QR for card:", qrCode._id);
                const signed = await signQr({ cardId: qrCode._id, purpose: "vms" });
                const qrData = signed?.data;
                console.log("[QR Print] signQr result:", signed, "| qrData:", qrData);
                if (!qrData) {
                  console.warn("[QR Print] Skipping card", qrCode._id, "— signQr returned no data.");
                  continue;
                }
                console.log("[QR Print] Sending to printer — accessLevel:", qrCode.accessLevel, "liftLevel:", qrCode.liftAccessLevel);
                const printResult = await testConnection(
                  vendorId,
                  productId,
                  true,
                  qrData,
                  qrCode.accessLevel,
                  qrCode.liftAccessLevel,
                  companyName,
                  address,
                );
                console.log("[QR Print] Print result for card", qrCode._id, ":", printResult);
              }
            }
          }
        }
      }
      if (createMore.value) {
        emit("done:more");
      } else emit("done");
    }
  } catch (error: any) {
    const err = error?.data?.message;
    errorMessage.value =
      err ||
      `Failed to ${prop.mode === "add" ? "add" : "update"
      } visitor. Please try again.`;
  } finally {
    processing.value = false;
  }
}

watch(
  () => visitor.plateNumber,
  (newVal) => {
    visitor.plateNumber = newVal?.toUpperCase();
  }
);

const membersFieldIncomplete = computed(() => {
  if (!visitor.members || visitor.members.length === 0) return false;

  return visitor.members.some((member) => {
    const hasName = !!member.name;
    const hasNric = !!member.nric;
    const hasContact = !!member.contact;

    return !hasName || !hasNric || !hasContact;
  });
});

onMounted(() => {
  contractorStep.value = 1;
  currentAutofillSource.value = null;

  if (prop.mode === 'register' && prop.visitorData) {
    console.log('Register mode, prefill visitor data', prop.visitorData?.plateNumber)
    visitor.plateNumber = prop.visitorData?.plateNumber || ""
  }
});
</script>
<style scoped>
.button-outline-class {
  border: 1px solid rgba(var(--v-theme-primary));
}

.no-pointer {
  pointer-events: none;
}
</style>
