<template>
  <v-row no-gutters>
    <v-col cols="12" class="mb-2" v-if="canCreate || $slots.actions">
      <v-row no-gutters>
        <slot name="actions">
          <v-btn
            v-if="canCreate"
            class="text-none"
            rounded="pill"
            variant="tonal"
            size="large"
            @click="emits('create')"
          >
            {{ createLabel }}
          </v-btn>
        </slot>
      </v-row>
    </v-col>

    <v-col cols="12">
      <v-card
        width="100%"
        variant="outlined"
        border="thin"
        rounded="lg"
        :loading="loading"
      >
        <v-toolbar
          density="compact"
          color="grey-lighten-4"
          :extension-height="extensionHeight"
        >
          <template #prepend>
            <v-btn fab icon density="comfortable" @click="emits('refresh')">
              <v-icon>mdi-refresh</v-icon>
            </v-btn>
            <slot name="prepend-additional" />
          </template>

          <v-toolbar-title
            v-if="title"
            class="text-subtitle-1 font-weight-medium"
          >
            {{ title }}
          </v-toolbar-title>

          <template #append>
            <v-row no-gutters justify="end" align="center">
              <span class="mr-2 text-caption text-fontgray">
                {{ pageRange }}
              </span>
              <local-pagination
                v-model="internalPage"
                :length="pages"
                @update:value="emits('update:page', internalPage)"
              />
            </v-row>
          </template>

          <template v-if="$slots.extension" #extension>
            <slot name="extension" />
          </template>
        </v-toolbar>

        <v-divider />

        <v-sheet
          :max-height="`calc(100vh - (${offset}px))`"
          class="overflow-y-auto"
        >
          <v-row
            v-if="groupedItems.length === 0"
            no-gutters
            justify="center"
            class="py-10"
          >
            <v-col
              cols="auto"
              class="text-center text-medium-emphasis text-body-2"
            >
              {{ noDataText }}
            </v-col>
          </v-row>

          <template
            v-for="(group, groupIndex) in groupedItems"
            :key="`group-${groupIndex}`"
          >
            <v-sheet color="grey-lighten-4" border="b t">
              <v-row no-gutters align="center" class="px-4 py-2">
                <v-col cols="auto" class="d-flex align-center ga-2">
                  <span
                    class="text-caption font-weight-bold text-medium-emphasis text-uppercase"
                  >
                    Set {{ group.set }}
                  </span>
                  <v-chip
                    v-if="group.isScheduleTask"
                    size="x-small"
                    color="info"
                    variant="tonal"
                    prepend-icon="mdi-calendar-clock"
                    class="text-none"
                  >
                    Schedule Task
                  </v-chip>
                  <slot name="group-header-chips" :group="group">
                    <v-chip
                      v-if="group.completedByName && isGroupComplete(group)"
                      size="x-small"
                      color="success"
                      variant="tonal"
                      prepend-icon="mdi-check-circle-outline"
                      class="text-none"
                    >
                      Completed · {{ group.completedByName }}
                    </v-chip>
                    <v-chip
                      v-else-if="
                        group.completedByName && isGroupInProgress(group)
                      "
                      size="x-small"
                      color="warning"
                      variant="tonal"
                      prepend-icon="mdi-progress-clock"
                      class="text-none"
                    >
                      Ongoing · {{ group.completedByName }}
                    </v-chip>
                  </slot>
                </v-col>
                <v-spacer />
                <v-col cols="auto">
                  <slot name="group-header-append" :group="group" />
                </v-col>
              </v-row>
            </v-sheet>

            <v-sheet
              v-for="item in group.items"
              :key="item[itemValue]"
              color="white"
              border="b"
            >
              <v-row no-gutters align="center" class="px-4 py-2">
                <v-col cols="auto" class="mr-3">
                  <slot name="item-prepend" :item="item" :group="group" />
                </v-col>

                <v-col>
                  <slot name="item-content" :item="item" :group="group">
                    <v-row no-gutters>
                      <v-col cols="12">
                        <span class="text-body-2 font-weight-medium">
                          {{ getItemValue(item, headers[0]?.value) }}
                        </span>
                      </v-col>
                      <v-col
                        v-if="
                          item.timestamp ||
                          (headers[1] &&
                            getItemValue(item, headers[1].value)) ||
                          (headers[2] && getItemValue(item, headers[2].value))
                        "
                        cols="12"
                      >
                        <v-row
                          no-gutters
                          align="center"
                          class="ga-3 flex-wrap mt-1"
                        >
                          <v-col
                            v-if="item.timestamp"
                            cols="auto"
                            class="d-flex align-center ga-1 text-caption text-medium-emphasis pa-0"
                          >
                            <v-icon size="11">mdi-clock-outline</v-icon>
                            {{ formatTimestamp(item.timestamp) }}
                          </v-col>
                          <v-col
                            v-if="
                              headers[1] && getItemValue(item, headers[1].value)
                            "
                            cols="auto"
                            class="text-caption text-medium-emphasis pa-0"
                          >
                            {{ getItemValue(item, headers[1].value) }}
                          </v-col>
                          <v-col
                            v-if="
                              headers[2] && getItemValue(item, headers[2].value)
                            "
                            cols="auto"
                            class="text-caption text-medium-emphasis pa-0"
                          >
                            {{ getItemValue(item, headers[2].value) }}
                          </v-col>
                        </v-row>
                      </v-col>
                    </v-row>
                  </slot>
                </v-col>

                <v-col cols="auto">
                  <slot name="item-append" :item="item" :group="group" />
                </v-col>
              </v-row>
            </v-sheet>
          </template>
        </v-sheet>

        <slot name="footer" />
      </v-card>
    </v-col>
  </v-row>
</template>

<script lang="ts" setup>
defineOptions({ inheritAttrs: false });

const props = defineProps({
  title: {
    type: String,
    default: "",
  },
  noDataText: {
    type: String,
    default: "No data available",
  },
  headers: {
    type: Array as PropType<Array<Record<string, any>>>,
    required: true,
  },
  items: {
    type: Array as PropType<Array<Record<string, any>>>,
    default: () => [],
  },
  loading: {
    type: Boolean,
    default: false,
  },
  canCreate: {
    type: Boolean,
    default: false,
  },
  createLabel: {
    type: String,
    default: "Add",
  },
  itemValue: {
    type: String,
    default: "_id",
  },
  itemsPerPage: {
    type: Number,
    default: 20,
  },
  page: {
    type: Number,
    default: 1,
  },
  pages: {
    type: Number,
    default: 0,
  },
  pageRange: {
    type: String,
    default: "-- - -- of --",
  },
  showHeader: {
    type: Boolean,
    default: false,
  },
  extensionHeight: {
    type: Number,
    default: 50,
  },
  offset: {
    type: Number,
    default: 200,
  },
});

const emits = defineEmits(["create", "refresh", "update:page"]);

const internalPage = ref(props.page);
const itemOrderMap = new Map<string, number>();

const groupedItems = computed(() => {
  return props.items.map((item: any) => {
    const units = item.units || [item];

    units.forEach((unit: any) => {
      const key = `${unit[props.itemValue]}_${item.set}`;
      if (!itemOrderMap.has(key)) {
        itemOrderMap.set(key, itemOrderMap.size);
      }
    });

    const sortedUnits = [...units].sort((a: any, b: any) => {
      const keyA = `${a[props.itemValue]}_${item.set}`;
      const keyB = `${b[props.itemValue]}_${item.set}`;
      return (itemOrderMap.get(keyA) ?? 0) - (itemOrderMap.get(keyB) ?? 0);
    });

    return {
      set: item.set,
      isScheduleTask: item.isScheduleTask ?? false,
      completedByName: item.completedByName ?? null,
      attachments:
        (item.attachment as string[] | undefined) ??
        (item.attachments as string[] | undefined) ??
        [],
      items: sortedUnits,
    };
  });
});

function formatTimestamp(ts: string): string {
  if (!ts) return "";
  const date = new Date(ts);
  return date.toLocaleString("en-SG", {
    day: "2-digit",
    month: "short",
    year: "numeric",
    hour: "2-digit",
    minute: "2-digit",
    hour12: true,
  });
}

function isGroupComplete(group: { items: any[] }): boolean {
  return (
    group.items.length > 0 &&
    group.items.every((item: any) => item.approve === true)
  );
}

function isGroupInProgress(group: { items: any[] }): boolean {
  return (
    group.items.some(
      (item: any) => item.approve === true || item.reject === true
    ) && !isGroupComplete(group)
  );
}

function getItemValue(item: any, key: string): string {
  if (!key) return "";
  return key.split(".").reduce((obj: any, k: string) => obj?.[k], item) ?? "";
}

watch(
  () => props.page,
  (val) => {
    internalPage.value = val;
    itemOrderMap.clear();
  }
);
</script>
