<template>
  <v-row no-gutters align="center" justify="center">
    <v-col cols="12" lg="12">
      <v-row no-gutters class="mb-4">
        <v-col cols="auto">
          <v-btn variant="text" color="primary" class="text-none" @click="back">
            <v-icon left>mdi-arrow-left</v-icon>
            Back
          </v-btn>
        </v-col>
        <v-spacer />
        <v-col v-if="isScheduleClosed" cols="auto" class="d-flex align-center">
          <v-chip color="error" variant="tonal" class="text-capitalize">
            <v-icon start>mdi-lock</v-icon>
            Closed – View Only
          </v-chip>
        </v-col>
      </v-row>
      <TableHygiene
        :title="scheduleTitle"
        :headers="headers"
        :items="items"
        :item-value="'unit'"
        v-model:page="page"
        :pages="pages"
        :pageRange="pageRange"
        :loading="loading"
        :no-data-text="`No checklist found`"
        :show-header="true"
        @refresh="getUnitCleanerChecklistRefresh"
      >
        <!-- Status icon driven by local activeActions state -->
        <template #item-prepend="{ item, group }">
          <v-icon
            size="20"
            :color="
              activeActions[getKey(item, group.set)] === 'approve'
                ? 'success'
                : activeActions[getKey(item, group.set)] === 'reject'
                ? 'error'
                : 'grey-lighten-2'
            "
          >
            {{
              activeActions[getKey(item, group.set)] === "approve"
                ? "mdi-check-circle"
                : activeActions[getKey(item, group.set)] === "reject"
                ? "mdi-close-circle"
                : "mdi-circle-outline"
            }}
          </v-icon>
        </template>

        <!-- Item name with strike-through when approved -->
        <template #item-content="{ item, group }">
          <v-row no-gutters>
            <v-col cols="12">
              <span
                class="text-body-2 font-weight-medium"
                :class="
                  activeActions[getKey(item, group.set)] === 'approve'
                    ? 'text-decoration-line-through text-medium-emphasis'
                    : ''
                "
              >
                {{ item.name }}
              </span>
            </v-col>
            <v-col v-if="item.timestamp" cols="12">
              <v-row no-gutters align="center" class="mt-1">
                <v-col
                  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-row>
            </v-col>
          </v-row>
        </template>

        <!-- Approve / Reject action buttons -->
        <template #item-append="{ item, group }">
          <v-row
            v-if="!isScheduleClosed && canManageScheduleTasks"
            no-gutters
            align="center"
          >
            <v-col cols="auto">
              <v-btn
                icon="mdi-close"
                size="small"
                :variant="
                  activeActions[getKey(item, group.set)] === 'reject'
                    ? 'flat'
                    : 'text'
                "
                color="error"
                @click.stop="handleItemActionClick(item, group.set, 'reject')"
              />
            </v-col>
            <v-col cols="auto">
              <v-btn
                icon="mdi-check"
                size="small"
                :variant="
                  activeActions[getKey(item, group.set)] === 'approve'
                    ? 'flat'
                    : 'text'
                "
                color="success"
                :loading="!!loadingActions[getKey(item, group.set)]"
                :disabled="!!loadingActions[getKey(item, group.set)]"
                @click.stop="handleItemActionClick(item, group.set, 'approve')"
              />
            </v-col>
          </v-row>
        </template>
        <template #group-header-chips> </template>
        <template #group-header-append="{ group }">
          <v-row no-gutters align="center" class="ga-2">
            <v-col v-if="isGroupAnyApproved(group)" cols="auto">
              <v-chip
                size="x-small"
                :color="isGroupComplete(group) ? 'success' : 'warning'"
                variant="tonal"
                :prepend-icon="
                  isGroupComplete(group)
                    ? 'mdi-check-circle-outline'
                    : 'mdi-progress-clock'
                "
                class="text-none"
              >
                {{ isGroupComplete(group) ? "Completed" : "Ongoing" }}
                <template v-if="getGroupCompletedByName(group)">
                  · {{ getGroupCompletedByName(group) }}
                </template>
              </v-chip>
            </v-col>
            <v-col
              v-if="group.attachments && group.attachments.length > 0"
              cols="auto"
            >
              <v-btn
                size="x-small"
                variant="tonal"
                color="primary"
                class="text-none"
                prepend-icon="mdi-paperclip"
                @click.stop="openAttachmentDialog(group.set, group.attachments)"
              >
                {{ group.attachments.length }} attachment{{
                  group.attachments.length > 1 ? "s" : ""
                }}
              </v-btn>
            </v-col>
          </v-row>
        </template>
      </TableHygiene>
    </v-col>
  </v-row>

  <v-dialog v-model="showCompletionModal" max-width="600" persistent>
    <v-card>
      <v-card-title class="text-h5 pa-4">
        {{
          modalData.currentSet !== undefined
            ? `Set ${modalData.currentSet} Completed`
            : "All Items Checked"
        }}
      </v-card-title>

      <v-divider />

      <v-card-text class="pa-4">
        <v-row>
          <v-col cols="12">
            <InputLabel
              title="Remarks (Optional)"
              :required="false"
              class="mb-2"
            />
            <v-textarea
              v-model="modalData.remark"
              placeholder="Enter your remarks here"
              rows="4"
              variant="outlined"
              density="comfortable"
              hide-details
            />
          </v-col>

          <v-col cols="12">
            <v-divider class="mb-4" />
            <PhotoUpload
              title="Take/Upload Photo"
              :required="false"
              v-model="modalData.photos"
              v-model:photo-ids="modalData.photoIds"
              @error="handlePhotoError"
            />
          </v-col>
        </v-row>
      </v-card-text>

      <v-divider />

      <v-card-actions class="pa-4">
        <v-spacer />
        <v-btn color="grey" variant="text" @click="closeModal"> Cancel </v-btn>
        <v-btn
          color="primary"
          variant="flat"
          @click="submitModal"
          :disabled="!isModalValid"
        >
          Submit
        </v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>

  <v-dialog v-model="showAttachmentDialog" max-width="700" scrollable>
    <v-card>
      <v-card-title class="d-flex align-center pa-4">
        <span class="text-h6 font-weight-bold">
          Set {{ attachmentDialogSetNum }} — Attachments
        </span>
        <v-spacer />
        <v-btn
          icon="mdi-close"
          variant="text"
          size="small"
          @click="showAttachmentDialog = false"
        />
      </v-card-title>

      <v-divider />

      <v-card-text class="pa-4">
        <v-row>
          <v-col
            v-for="(id, index) in attachmentDialogIds"
            :key="index"
            cols="6"
            sm="4"
          >
            <v-sheet
              rounded="lg"
              class="overflow-hidden"
              style="aspect-ratio: 1"
            >
              <v-img
                :src="getFileUrl(id)"
                aspect-ratio="1"
                cover
                class="rounded-lg"
                @click="openFullImage(getFileUrl(id))"
                style="cursor: zoom-in"
              >
                <template v-slot:placeholder>
                  <v-row
                    class="fill-height ma-0"
                    align="center"
                    justify="center"
                  >
                    <v-progress-circular indeterminate color="grey-lighten-4" />
                  </v-row>
                </template>
                <template v-slot:error>
                  <v-row
                    class="fill-height ma-0"
                    align="center"
                    justify="center"
                  >
                    <v-icon icon="mdi-image-broken" size="40" color="grey" />
                  </v-row>
                </template>
              </v-img>
            </v-sheet>
          </v-col>
        </v-row>
      </v-card-text>
    </v-card>
  </v-dialog>

  <v-dialog v-model="showLightbox" max-width="900">
    <v-card>
      <v-card-actions class="pa-2 justify-end">
        <v-btn icon="mdi-close" variant="text" @click="showLightbox = false" />
      </v-card-actions>
      <v-card-text class="pa-2 pt-0">
        <v-img :src="lightboxSrc" contain max-height="80vh" />
      </v-card-text>
    </v-card>
  </v-dialog>

  <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
</template>

<script setup lang="ts">
import useCleaningSchedules from "../composables/useCleaningSchedules";
import useCustomerSite from "../composables/useCustomerSite";
import useFile from "../composables/useFile";
import useUtils from "../composables/useUtils";

const props = defineProps({
  orgId: { type: String, default: "" },
  site: { type: String, default: "" },
  cleanerChecklistId: { type: String, default: "" },
  scheduleAreaId: { type: String, default: "" },
  type: { type: String, default: "cleaner" },
  serviceType: { type: String, default: "" },
  canAddRemarks: { type: Boolean, default: false },
  canManageScheduleTasks: { type: Boolean, default: false },
});

const { getUnitCleanerChecklist, updateUnitChecklist } = useCleaningSchedules();
const { getBySiteAsServiceProvider } = useCustomerSite();
const { back } = useUtils();

const route = useRoute();
const scheduleTitle = computed(() => {
  const path = route.path;
  if (path.includes('cleaning-schedule')) return 'Cleaning Checklist';
  if (path.includes('technician-schedule')) return 'Technician Checklist';
  if (path.includes('landscape-schedule')) return 'Landscape Checklist';
  if (path.includes('pool-schedule')) return 'Pool Checklist';
  if (path.includes('pest-schedule')) return 'Pest Checklist';
  return 'Cleaner Checklist';
});

const canAddRemarks = computed(() => props.canAddRemarks);
const canManageScheduleTasks = computed(() => props.canManageScheduleTasks);

const selectedScheduleStatus = useState<string>(
  "selectedScheduleStatus",
  () => ""
);
const isScheduleClosed = computed(
  () => selectedScheduleStatus.value.toLowerCase() === "closed"
);

const page = ref<number>(1);
const pages = ref<number>(0);
const pageRange = ref<string>("-- - -- of --");
const items = ref<TChecklistSet[]>([]);
const selectedItems = ref<Array<{ unit: string; set: number }>>([]);
const submitting = ref<boolean>(false);
const message = ref<string>("");
const messageSnackbar = ref<boolean>(false);
const messageColor = ref<string>("");
const categories = ref<
  Array<{ title: string; value: string; subtitle: string }>
>([]);
const headers = [{ title: "Name", value: "name" }];

// ── Action state (approve / reject per item key) ───────────────────────────
const activeActions = reactive<Record<string, "approve" | "reject">>({});
const persistedActions = reactive<Record<string, "approve" | "reject">>({});
const loadingActions = reactive<Record<string, boolean>>({});
const completedSets = ref<Set<number>>(new Set());
const lastApprovedKey = ref<string | null>(null);

function getKey(item: any, set?: number): string {
  return `${item.unit}_${set ?? ""}`;
}

function isGroupComplete(group: { set: number; items: any[] }): boolean {
  return (
    group.items.length > 0 &&
    group.items.every(
      (item: any) =>
        item.approve === true ||
        activeActions[getKey(item, group.set)] === "approve"
    )
  );
}

function isGroupAnyApproved(group: { set: number; items: any[] }): boolean {
  return group.items.some(
    (item: any) =>
      item.approve === true ||
      activeActions[getKey(item, group.set)] === "approve"
  );
}

function getGroupCompletedByName(group: {
  completedByName: string | null;
  items: any[];
}): string | null {
  return (
    group.completedByName ??
    group.items.find((item: any) => item.completedByName)?.completedByName ??
    null
  );
}

function isSetFullyApproved(setNumber: number): boolean {
  const group = items.value.find((g: any) => g.set === setNumber);
  if (!group) return false;
  return (group.units || []).every(
    (unit: any) => activeActions[getKey(unit, setNumber)] === "approve"
  );
}

function getNewApprovedItemsForSet(
  setNumber: number
): Array<{ key: string; item: any; action: "approve" }> {
  const group = items.value.find((g: any) => g.set === setNumber);
  if (!group) return [];
  return (group.units || [])
    .filter((unit: any) => {
      const key = getKey(unit, setNumber);
      return activeActions[key] === "approve" && !(key in persistedActions);
    })
    .map((unit: any) => ({
      key: getKey(unit, setNumber),
      item: { ...unit, set: setNumber },
      action: "approve" as const,
    }));
}

function revertSetApprovals(setNumber: number): void {
  const group = items.value.find((g: any) => g.set === setNumber);
  if (group) {
    (group.units || []).forEach((unit: any) => {
      const key = getKey(unit, setNumber);
      if (!(key in persistedActions)) {
        delete activeActions[key];
      }
    });
  }
  completedSets.value.delete(setNumber);
}

function stopLoadingAction(key: string): void {
  delete loadingActions[key];
}

// ── Attachment dialog ──────────────────────────────────────────────────────
const showAttachmentDialog = ref(false);
const attachmentDialogSetNum = ref<number | undefined>(undefined);
const attachmentDialogIds = ref<string[]>([]);
const showLightbox = ref(false);
const lightboxSrc = ref("");

const { getFileUrl } = useFile();

function openAttachmentDialog(setNumber: number, attachments: string[]) {
  attachmentDialogSetNum.value = setNumber;
  attachmentDialogIds.value = attachments;
  showAttachmentDialog.value = true;
}

function openFullImage(src: string) {
  lightboxSrc.value = src;
  showLightbox.value = true;
}

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,
  });
}

const { data: getCategoriesReq } = await useLazyAsyncData(
  "get-categories-for-work-order",
  () => getBySiteAsServiceProvider(props.site)
);

// Modal state management
const showCompletionModal = ref<boolean>(false);
const modalData = reactive({
  remark: "",
  photos: [] as string[],
  photoIds: [] as string[],
  currentSet: undefined as number | undefined,
  approvedItems: [] as Array<{ key: string; item: any; action: "approve" }>,
  lastApprovedKey: null as string | null,
});

const isModalValid = computed(() => {
  return modalData.remark?.trim().length > 0;
});

const {
  data: getUnitCleanerChecklistReq,
  refresh: getUnitCleanerChecklistRefresh,
  pending: loading,
} = await useLazyAsyncData(
  `get-all-unit-cleaner-checklist`,
  () =>
    getUnitCleanerChecklist({
      page: page.value,
      scheduleAreaId: props.scheduleAreaId,
      serviceType: props.serviceType,
    }),
  {
    watch: [() => page.value, () => props.scheduleAreaId],
  }
);

watchEffect(() => {
  const data = getCategoriesReq.value as any;
  if (data) {
    categories.value = (data.categories ?? data).map((cat: any) => ({
      title: cat.name,
      value: cat.id,
      subtitle: cat.description || "",
    }));
  }
});

watchEffect(() => {
  if (getUnitCleanerChecklistReq.value) {
    items.value = getUnitCleanerChecklistReq.value.items;
    page.value = getUnitCleanerChecklistReq.value.page;
    pages.value = getUnitCleanerChecklistReq.value.pages;
    pageRange.value = getUnitCleanerChecklistReq.value.pageRange;
  }
});

watchEffect(() => {
  const completed: Array<{ unit: string; set: number }> = [];

  items.value.forEach((checklistSet: TChecklistSet) => {
    checklistSet.units?.forEach((unit: TUnitChecklistItem) => {
      if (
        unit.status?.toLowerCase() === "completed" ||
        (unit as any).approve === true
      ) {
        completed.push({ unit: unit.unit, set: checklistSet.set });
      }
    });
  });

  selectedItems.value = completed;
});

watch(
  items,
  (newItems) => {
    if (!Array.isArray(newItems)) return;

    Object.keys(persistedActions).forEach(
      (key) => delete persistedActions[key]
    );

    newItems.forEach((group: any) => {
      const set = group.set;
      (group.units || []).forEach((unit: any) => {
        const key = getKey(unit, set);
        if ((unit as any).approve === true) {
          activeActions[key] = "approve";
          persistedActions[key] = "approve";
        } else if ((unit as any).reject === true) {
          activeActions[key] = "reject";
          persistedActions[key] = "reject";
        }
      });
    });

    completedSets.value.clear();
    Object.keys(loadingActions).forEach((k) => delete loadingActions[k]);
  },
  { immediate: true }
);

function showMessage(msg: string, color: string = "error"): void {
  message.value = msg;
  messageColor.value = color;
  messageSnackbar.value = true;
}

function resetModalData(): void {
  modalData.remark = "";
  modalData.photos = [];
  modalData.photoIds = [];
  modalData.currentSet = undefined;
  modalData.approvedItems = [];
  modalData.lastApprovedKey = null;
}

function closeModal(): void {
  const setNumber = modalData.currentSet;
  showCompletionModal.value = false;
  resetModalData();

  // Revert optimistic approval state for this set
  if (setNumber !== undefined) {
    revertSetApprovals(setNumber);
  }
}

function handlePhotoError(errorMessage: string): void {
  console.error("Photo upload error:", errorMessage);
  showMessage(errorMessage, "error");
}

function openCompletionDialog({
  setNumber,
  approvedItems,
  lastApprovedKey,
}: {
  setNumber: number | undefined;
  approvedItems: Array<{ key: string; item: any; action: "approve" }>;
  lastApprovedKey: string | null;
}): void {
  if (isScheduleClosed.value) {
    showMessage(
      "This schedule is closed. No actions can be performed.",
      "error"
    );
    return;
  }

  // If user does not need to add remarks, perform approvals immediately
  if (!canAddRemarks.value) {
    // call update directly without opening modal
    _updateUnitChecklist({
      remark: "",
      photos: [],
      photoIds: [],
      approvedItems,
      lastApprovedKey,
      setNumber,
    }).catch((err) => {
      console.error("Error auto-approving set:", err);
      showMessage(err?.message || "Failed to approve set", "error");
    });
    return;
  }

  modalData.currentSet = setNumber;
  modalData.approvedItems = approvedItems;
  modalData.lastApprovedKey = lastApprovedKey;
  showCompletionModal.value = true;
}

async function submitModal(): Promise<void> {
  if (!isModalValid.value) return;

  await _updateUnitChecklist({
    remark: modalData.remark,
    photos: modalData.photos,
    photoIds: modalData.photoIds,
    approvedItems: modalData.approvedItems,
    lastApprovedKey: modalData.lastApprovedKey,
    setNumber: modalData.currentSet,
  });

  closeModal();
}

async function handleItemActionClick(
  item: TUnitChecklistItem,
  set: number | undefined,
  action: "approve" | "reject"
): Promise<void> {
  if (isScheduleClosed.value) {
    showMessage(
      "This schedule is closed. No actions can be performed.",
      "error"
    );
    return;
  }

  if (!item?.unit || set === undefined) {
    showMessage("Invalid unit or set", "error");
    return;
  }

  const key = getKey(item, set);
  const isPersisted = key in persistedActions;

  // Toggle off optimistic state if clicking the same un-persisted action
  if (activeActions[key] === action && !isPersisted) {
    delete activeActions[key];
    return;
  }

  activeActions[key] = action;

  if (action === "reject") {
    await _callUpdateUnitChecklist(item, set, action);
    return;
  }

  // Approve: check if this completes the entire set
  lastApprovedKey.value = key;

  if (isSetFullyApproved(set) && !completedSets.value.has(set)) {
    const newApprovedItems = getNewApprovedItemsForSet(set);
    if (newApprovedItems.length > 0) {
      completedSets.value.add(set);
      openCompletionDialog({
        setNumber: set,
        approvedItems: newApprovedItems,
        lastApprovedKey: lastApprovedKey.value,
      });
      return;
    }
  }

  // Single item approve (does not complete the set yet)
  if (!isPersisted) {
    delete activeActions[key];
    loadingActions[key] = true;
  }

  await _callUpdateUnitChecklist(item, set, action);
}

async function _callUpdateUnitChecklist(
  item: TUnitChecklistItem,
  set: number,
  action: "approve" | "reject"
): Promise<void> {
  const isApproved = selectedItems.value.some(
    (s) => s.unit === item.unit && s.set === set
  );
  if (isApproved && action === "approve") {
    showMessage("Unit already approved", "info");
    return;
  }

  submitting.value = true;

  try {
    const response = await updateUnitChecklist(
      props.scheduleAreaId,
      item.unit,
      set,
      action
    );
    showMessage(
      response?.message ||
        `Unit ${action === "approve" ? "approved" : "rejected"} successfully`,
      "success"
    );
    await getUnitCleanerChecklistRefresh();
  } catch (error: any) {
    console.error("Error updating unit checklist:", error);
    showMessage(
      error?.data?.message || error?.message || "Failed to update checklist",
      "error"
    );
  } finally {
    submitting.value = false;
    if (action === "approve") {
      stopLoadingAction(getKey(item, set));
    }
  }
}

async function _updateUnitChecklist({
  remark,
  photoIds,
  approvedItems,
  setNumber,
}: {
  remark: string;
  photos: string[];
  photoIds: string[];
  approvedItems: Array<{ key: string; item: any; action: "approve" }>;
  lastApprovedKey: string | null;
  setNumber: number | undefined;
}) {
  submitting.value = true;

  try {
    if (!approvedItems || approvedItems.length === 0) {
      throw new Error("No items to approve");
    }

    if (!remark?.trim()) {
      throw new Error("Remark is required");
    }

    const checklistId = props.scheduleAreaId;

    for (let i = 0; i < approvedItems.length; i++) {
      const { item } = approvedItems[i];
      const unitId = item.unit;
      const setNum = item.set;
      const isLastItem = i === approvedItems.length - 1;

      await updateUnitChecklist(
        checklistId,
        unitId,
        setNum,
        "approve",
        isLastItem ? remark : undefined,
        isLastItem ? photoIds : undefined
      );
    }

    showMessage(`Set ${setNumber} approved successfully`, "success");

    // Refresh data
    await getUnitCleanerChecklistRefresh();
  } catch (error: any) {
    console.error("Error approving set:", error);
    showMessage(error?.message || "Failed to approve set", "error");
  } finally {
    submitting.value = false;
  }
}
</script>
