<template>
  <div class="gantt-container">
    <div class="gantt-header">
      <!-- Calendar: เชื่อมกับ selectedDate -->
      <GanttCalendar />

      <!-- ปุ่มจัดเรียงและเพิ่มระยะห่าง -->
      <div class="gantt-buttons">
        <MakequeueBtn />
        <SettingBtn class="mr-4" />
      </div>
    </div>

    <!-- Gantt Chart UI -->
    <div class="gantt-chart">
      <!-- Header: Time Scale -->
      <div class="header">
        <div class="machine-label"></div>
        <div class="time-scale">
          <div v-for="hour in hours" :key="hour" class="time-cell">
            {{ formatHour(hour) }}
          </div>
        </div>
      </div>

      <!-- Rows: แสดงเครื่องจักรจาก Machine Store -->
      <div class="rows">
        <div v-for="machine in machineStore.machines" :key="machine.MachineID" class="row"
          :data-machine-id="machine.MachineID" @dragover.prevent="onDragOver($event)"
          @drop="onDrop($event, machine.MachineID)">
          <div class="machine-label">
            {{ machine.name }}
          </div>
          <div class="row-timeline">
            <!-- เส้นแนวตั้ง (Grid Lines) -->
            <div v-for="hour in hours" :key="'line-' + hour" class="vertical-line" :style="getLineStyle(hour)"></div>

            <!-- แสดง Queue ที่ตรงกับวันที่ (selectedDate), Page (pagenum), และ Machine -->
            <div v-for="item in filteredQueue(machine.MachineID)" :key="item.QueueID" class="order"
              :class="{ faded: draggingQueue && draggingQueue.QueueID === item.QueueID }" :style="getQueueStyle(item)">
              <!-- Handle สำหรับ Resize ด้านซ้าย -->
              <div class="resize-handle left" @mousedown="onResizeStart($event, item, 'left')"></div>
              <!-- ส่วนกลางของ Order ใช้สำหรับลาก และเปิด Dialog เมื่อคลิก -->
              <div class="order-content" draggable="true" @dragstart="onDragStart($event, item)"
                @dragend="onDragEnd($event, item)" @click.stop="openQueueDialog(item)">
                {{ item.label }} ({{ getTimeString(item.startTime) }} - {{ getTimeString(item.finishTime) }})
              </div>
              <!-- Handle สำหรับ Resize ด้านขวา -->
              <div class="resize-handle right" @mousedown="onResizeStart($event, item, 'right')"></div>
            </div>
          </div>
        </div>
      </div>

      <!-- Ghost Queue (ขณะลาก/resize) -->
      <div v-if="ghostQueue" class="drag-ghost" :style="ghostStyle">
        {{ ghostQueue.label }} ({{ getTimeString(ghostQueue.startTime) }} - {{ getTimeString(ghostQueue.finishTime) }})
      </div>

      <v-divider :thickness="7"></v-divider>

      <!-- Pagination -->
      <div class="pagination-container">
        <transition-group name="fade" tag="div" class="pagination">
          <button v-for="p in pages" :key="p" :class="['page-btn', { active: p === currentPage }]"
            @click="currentPage = p" @contextmenu.prevent="onPageRightClick(p, $event)">
            {{ p }}
            <button v-if="pageToShowDelete === p" class="delete-btn" @click.stop="deletePage(p)">
              Delete
            </button>
          </button>
          <button class="page-btn add-page" @click="addPage" :disabled="pages.length >= 10">
            +
          </button>
        </transition-group>
        <div class="pagination-right">
          <v-btn class="add-page-btn" @click="openAddQueueDialog" icon>
            <v-icon>mdi-plus</v-icon>
          </v-btn>
        </div>
        <AddQueueDialog :visible="showAddDialog" :queueItem="selectedQueueItem" :currentPage="currentPage"
          @close="closeAddQueueDialog" />
      </div>
      <OrderDialog v-if="selectedQueueItem && !showAddDialog" :queueId="selectedQueueItem.QueueID"
        :color="getQueueColor(selectedQueueItem.QueueID)" @close="closeQueueDialog" @edit="openAddQueueDialogForEdit"
        @delete="handleDelete" />
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref, reactive, computed, onMounted, onBeforeUnmount, watch } from 'vue';
import { useQueueStore } from '@/stores/queue';
import { useMachineStore } from '@/stores/machine';
import { usePageStore } from '@/stores/page';
import { usePageContextStore } from '@/stores/pageContext';
import { useDateStore } from '@/stores/dateStore';
import { storeToRefs } from 'pinia';

import GanttCalendar from './GanttCalendar.vue';
import OrderDialog from './OrderDialog.vue';
import AddQueueDialog from './AddQueueDialog.vue';
import MakequeueBtn from './MakequeueBtn.vue';
import SettingBtn from './SettingBtn.vue';
import './ganttChart.css';

// Stores
const queueStore = useQueueStore();
const machineStore = useMachineStore();
const pageStore = usePageStore();
const dateStore = useDateStore();
const { currentDate: selectedDate } = storeToRefs(dateStore);
const pageContext = usePageContextStore();

// ใช้ currentPage เป็น pagenum จาก pageContext
const currentPage = computed({
  get: () => pageContext.currentPage,
  set: (val) => (pageContext.currentPage = val),
});

// เมื่อเข้าหน้า ให้ดึงข้อมูลจาก backend
onMounted(() => {
  machineStore.fetchMachines();
  queueStore.fetchQueues();
  pageStore.fetchPages();
});

// State สำหรับ Gantt Chart
const showAddDialog = ref(false);
const startTime = ref('06:00');
const endTime = ref('20:00');

const draggingQueue = ref<any | null>(null);
const dragOffset = ref(0);
const resizingQueue = ref<any | null>(null);
const resizeDirection = ref<string | null>(null);
const localQueueMap = ref<Record<number, any>>({});

const ghostQueue = ref<any | null>(null);
const ghostStyle = reactive({
  position: 'fixed',
  top: '0px',
  left: '0px',
  display: 'none',
  width: 'auto',
  height: '40px',
  lineHeight: '40px',
  padding: '0 10px',
  borderRadius: '10px',
  pointerEvents: 'none',
  backgroundColor: '#4caf50',
  color: '#fff',
  zIndex: 9999,
});

const originalLabelMap: Record<number, string> = {};
const originalColorMap: Record<number, string> = {};

// แปลงข้อมูล Queue จาก backend ให้เข้ากับรูปแบบที่ Gantt Chart ใช้
const formattedQueues = computed(() => {
  return queueStore.queues.map(q => {
    const isResizing = resizingQueue.value && resizingQueue.value.QueueID === q.QueueID;
    const local = localQueueMap.value[q.QueueID];

    const label =
      originalLabelMap[q.QueueID] ??
      (q.QueueType?.QueueTypeID === 2 ? 'ผลิตเผื่อ' :
        q.QueueType?.QueueTypeID === 3 ? 'เปลี่ยนขนาด' :
          local?.label || q.order?.customer?.name || 'Unknown');

    const color = originalColorMap[q.QueueID] ?? getQueueColor(label);

    const startTime = isResizing ? resizingQueue.value.startTime : convertToLocalTime(q.startTime);
    const finishTime = isResizing ? resizingQueue.value.finishTime : convertToLocalTime(q.finishTime);


    return {
      QueueID: q.QueueID,
      orderID: q.order?.OrderID || "Unknown",
      label,
      color,
      machineID: q.machine?.MachineID || 0,
      machineName: q.machine?.name || "Unknown Machine",
      startTime,
      finishTime,
      status: q.status || "Unknown",
      bottleSize: q.bottleSize || "Unknown",
      producedQuantity: q.producedQuantity || 0,
      pageNumber: q.page?.pagenum || 0,
      QueueTypeID: q.QueueType?.QueueTypeID || 0,
    };
  });
});




function clearOriginalMaps() {
  Object.keys(originalLabelMap).forEach((k) => delete originalLabelMap[+k]);
  Object.keys(originalColorMap).forEach((k) => delete originalColorMap[+k]);
}

function convertToLocalTime(utcString: string): string {
  const date = new Date(utcString);
  date.setHours(date.getHours() + 7);
  return date.toISOString().slice(0, 16).replace("T", " ");
}

// Pagination & Dialog
const pages = computed(() => pageStore.pages.map(p => p.pagenum));
const pageToShowDelete = ref<number | null>(null);
const selectedQueueItem = ref<any | null>(null);

watch(
  () => queueStore.queues,
  (newVal) => {
    console.log("🔄 Queues updated in GanttChart.vue:", newVal);
  },
  { deep: true }
);

const hours = computed(() => {
  const startHour = parseInt(startTime.value.split(':')[0]);
  const endHour = parseInt(endTime.value.split(':')[0]);
  return Array.from({ length: endHour - startHour + 1 }, (_, i) => startHour + i);
});

// Methods
function openQueueDialog(item: any) {
  selectedQueueItem.value = { ...item };
}
function closeQueueDialog() {
  selectedQueueItem.value = null;
}
function openAddQueueDialog() {
  selectedQueueItem.value = null;
  showAddDialog.value = true;
}
function openAddQueueDialogForEdit(queueItem: any) {
  selectedQueueItem.value = { ...queueItem };
  showAddDialog.value = true;
}
function handleDelete(queueItem: { QueueID: number; }) {
  if (!queueItem) return;
  queueStore
    .deleteQueue(queueItem.QueueID)
    .then(() => {
      console.log(`✅ Queue ID ${queueItem.QueueID} ถูกลบสำเร็จ`);
      closeAddQueueDialog();
    })
    .catch((error) => console.error(`❌ Error deleting queue:`, error));
}
function closeAddQueueDialog() {
  showAddDialog.value = false;
  selectedQueueItem.value = null;
}

function formatHour(hour: number): string {
  return (hour < 10 ? '0' + hour : hour) + ':00';
}
function getDateString(dateTimeStr: string): string {
  return dateTimeStr.split(' ')[0];
}
function getTimeString(dateTimeStr: string): string {
  return dateTimeStr.split(' ')[1];
}

function filteredQueue(machineID: number) {
  return formattedQueues.value.filter(q => {
    if (!q || !q.startTime || !q.finishTime) return false;
    const queueDate = getDateString(q.startTime);
    return (
      q.machineID === machineID &&
      q.pageNumber === currentPage.value &&
      queueDate === selectedDate.value
    );
  });
}

const colorMap: Record<string, string> = {};
function getQueueColor(label: string): string {
  if (label === "ผลิตเผื่อ") return "#FFC1C1";
  if (label === "เปลี่ยนขนาด") return "#E1BEE7";

  if (colorMap[label]) return colorMap[label];

  const newColor = generateWaterPastel();
  colorMap[label] = newColor;
  return newColor;
}

function generateWaterPastel(): string {
  const waterHues = [180, 190, 200, 210, 220, 230, 240];
  const hue = waterHues[Math.floor(Math.random() * waterHues.length)];
  return `hsl(${hue}, 60%, 80%)`;
}

function getQueueStyle(item: any) {
  const start = getTimeString(item.startTime);
  const end = getTimeString(item.finishTime);
  const startDecimal = timeToDecimal(start);
  const endDecimal = timeToDecimal(end);
  const totalHours = hours.value.length;
  const leftPercent = ((startDecimal - timeToDecimal(startTime.value)) / totalHours) * 100;
  const widthPercent = ((endDecimal - startDecimal) / totalHours) * 100;

  return {
    left: `${leftPercent}%`,
    width: `${widthPercent}%`,
    backgroundColor: item.color, // ✅ ใช้ field color
    color: '#333',
    borderRadius: '10px',
    textAlign: 'center',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    padding: '5px',
    fontSize: '14px',
    fontWeight: 'bold',
    boxShadow: '0px 4px 6px rgba(0, 0, 0, 0.1)',
  };
}




function getLineStyle(hour: number) {
  const totalHours = hours.value.length;
  const leftPercent = ((hour - timeToDecimal(startTime.value)) / totalHours) * 100;
  return { left: `${leftPercent}%` };
}
function timeToDecimal(timeStr: string): number {
  const [h, m] = timeStr.split(':').map(Number);
  return h + m / 60;
}
function decimalToTime(decimal: number): string {
  const hrs = Math.floor(decimal);
  const minutes = Math.round((decimal - hrs) * 60);
  return (hrs < 10 ? '0' + hrs : hrs) + ':' + (minutes < 10 ? '0' + minutes : minutes);
}

// Drag/Drop & Resize Functions
function onDragStart(event: DragEvent, item: any) {
  draggingQueue.value = item;
  const target = event.target as HTMLElement;
  const rect = target.getBoundingClientRect();
  dragOffset.value = rect.width / 2;
  const emptyImg = new Image();
  emptyImg.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
  event.dataTransfer?.setDragImage(emptyImg, 0, 0);

  // 🟢 Copy พร้อม label
  ghostQueue.value = { ...item, label: item.label };
  ghostStyle.display = 'block';
  ghostStyle.backgroundColor = getQueueColor(item.label); // เปลี่ยนจาก orderID เป็น label

  document.addEventListener('dragover', onDragOverGlobal);
  document.addEventListener('dragend', onDragEndGlobal);
}

function onDragOver(event: DragEvent) {
  event.preventDefault();
}
function onDragOverGlobal(event: DragEvent) {
  event.preventDefault();
  const rowTimeline = document.querySelector('.row-timeline') as HTMLElement;
  if (!rowTimeline) return;
  const timelineRect = rowTimeline.getBoundingClientRect();
  const timelineWidth = timelineRect.width;
  const offsetX = event.clientX - timelineRect.left;

  let ratio = offsetX / timelineWidth;
  ratio = Math.min(Math.max(ratio, 0), 1);

  const timelineStartDec = timeToDecimal(startTime.value);
  const timelineEndDec = timeToDecimal(endTime.value);
  if (!draggingQueue.value) return;
  const startDecimal = timeToDecimal(getTimeString(draggingQueue.value.startTime));
  const endDecimal = timeToDecimal(getTimeString(draggingQueue.value.finishTime));
  const duration = endDecimal - startDecimal;
  let newStartDecimal = timelineStartDec + ratio * (timelineEndDec - timelineStartDec);
  newStartDecimal = Math.round(newStartDecimal * 2) / 2;
  let newEndDecimal = newStartDecimal + duration;
  if (newEndDecimal > timelineEndDec) {
    newEndDecimal = timelineEndDec;
    newStartDecimal = newEndDecimal - duration;
  }

  const datePart = getDateString(draggingQueue.value.startTime);
  const newStartStr = datePart + ' ' + decimalToTime(newStartDecimal);
  const newEndStr = datePart + ' ' + decimalToTime(newEndDecimal);

  if (ghostQueue.value) {
    ghostQueue.value.startTime = newStartStr;
    ghostQueue.value.finishTime = newEndStr;
  }

  // คำนวณตำแหน่ง ghost element
  const snappedRatioStart = (newStartDecimal - timelineStartDec) / (timelineEndDec - timelineStartDec);
  const snappedLeft = timelineRect.left + snappedRatioStart * timelineWidth;
  const snappedRatioEnd = (newEndDecimal - timelineStartDec) / (timelineEndDec - timelineStartDec);
  const snappedWidth = (snappedRatioEnd - snappedRatioStart) * timelineWidth;

  // หาจุด row ที่ใกล้เคียงที่สุดและดึง machine id จาก attribute
  const rows = document.querySelectorAll('.row');
  let closestRow: HTMLElement | null = null;
  let minDistance = Infinity;
  rows.forEach((row) => {
    const rect = (row as HTMLElement).getBoundingClientRect();
    const distance = Math.abs(event.clientY - rect.top);
    if (distance < minDistance) {
      minDistance = distance;
      closestRow = row as HTMLElement;
    }
  });

  if (closestRow) {
    const machineIDString = (closestRow as HTMLElement).dataset.machineId;
    if (machineIDString) {
      ghostQueue.value.machineID = parseInt(machineIDString, 10);
    }
    ghostStyle.top = (closestRow as HTMLElement).getBoundingClientRect().top + 'px';
  }

  ghostStyle.left = snappedLeft + 'px';
  ghostStyle.width = snappedWidth + 'px';
}

function onDragEndGlobal() {
  ghostQueue.value = null;
  ghostStyle.display = 'none';
  draggingQueue.value = null;
  document.removeEventListener('dragend', onDragEndGlobal);
}

async function onDragEnd(event: DragEvent, item: any) {
  if (!ghostQueue.value) return;

  item.startTime = ghostQueue.value.startTime;
  item.finishTime = ghostQueue.value.finishTime;
  const newMachineID = ghostQueue.value.machine?.MachineID || item.machineID;

  // 🟡 Save original label & color
  originalLabelMap[item.QueueID] = item.label;
  originalColorMap[item.QueueID] = getQueueColor(item.label);

  await queueStore.updateQueue(item.QueueID, {
    startTime: item.startTime,
    finishTime: item.finishTime,
    MachineID: newMachineID,
  });

  await queueStore.fetchQueues();
  clearOriginalMaps();

  ghostQueue.value = null;
  ghostStyle.display = 'none';
  draggingQueue.value = null;
}



async function onDrop(event: DragEvent, newMachineID: number) {
  event.preventDefault();
  if (!draggingQueue.value || !ghostQueue.value) return;

  const queueID = draggingQueue.value.QueueID;

  // 🟡 Save label & color
  originalLabelMap[queueID] = draggingQueue.value.label;
  originalColorMap[queueID] = getQueueColor(draggingQueue.value.label);

  draggingQueue.value.startTime = ghostQueue.value.startTime;
  draggingQueue.value.finishTime = ghostQueue.value.finishTime;
  draggingQueue.value.machineID = newMachineID;

  try {
    await queueStore.updateQueue(queueID, {
      startTime: draggingQueue.value.startTime,
      finishTime: draggingQueue.value.finishTime,
      MachineID: newMachineID,
    });

    await queueStore.fetchQueues();
    clearOriginalMaps();

    delete originalLabelMap[queueID];
    delete originalColorMap[queueID];
  } catch (error) {
    console.error(`❌ Error updating queue:`, error);
  }

  ghostQueue.value = null;
  ghostStyle.display = 'none';
  draggingQueue.value = null;
}


function onResizeStart(event: MouseEvent, item: any, direction: string) {
  event.preventDefault();
  resizingQueue.value = item;
  resizeDirection.value = direction;

  // 🧠 เก็บสำเนาไว้ก่อนถูก fetch เคลียร์
  localQueueMap.value[item.QueueID] = { ...item };

  document.addEventListener('mousemove', onResizing);
  document.addEventListener('mouseup', onResizeEnd);
}



function onResizing(event: MouseEvent) {
  if (!resizingQueue.value) return;

  const rowTimeline = document.querySelector('.row-timeline') as HTMLElement;
  if (!rowTimeline) return;

  const timelineRect = rowTimeline.getBoundingClientRect();
  const timelineWidth = timelineRect.width;
  const offsetX = event.clientX - timelineRect.left;

  let ratio = offsetX / timelineWidth;
  ratio = Math.min(Math.max(ratio, 0), 1);

  const timelineStartDec = timeToDecimal(startTime.value);
  const timelineEndDec = timeToDecimal(endTime.value);

  let newTimeDecimal = timelineStartDec + ratio * (timelineEndDec - timelineStartDec);
  newTimeDecimal = Math.round(newTimeDecimal * 2) / 2; // snap 30 นาที

  const datePart = getDateString(resizingQueue.value.startTime);
  const startDec = timeToDecimal(getTimeString(resizingQueue.value.startTime));
  const endDec = timeToDecimal(getTimeString(resizingQueue.value.finishTime));

  if (resizeDirection.value === 'left') {
    if (newTimeDecimal >= endDec) return;
    resizingQueue.value.startTime = datePart + ' ' + decimalToTime(newTimeDecimal);
  } else if (resizeDirection.value === 'right') {
    if (newTimeDecimal <= startDec) return;
    resizingQueue.value.finishTime = datePart + ' ' + decimalToTime(newTimeDecimal);
  }
}



async function onResizeEnd() {
  if (!resizingQueue.value) return;

  const item = resizingQueue.value;

  try {
    await queueStore.updateQueue(item.QueueID, {
      startTime: item.startTime,
      finishTime: item.finishTime,
    });

    // ✅ ค่อย fetch หลัง update เสร็จ
    await queueStore.fetchQueues();
  } catch (error) {
    console.error('❌ Resize update failed:', error);
  } finally {
    // ✅ ย้ายมาปิดตรงนี้ เพื่อให้ formattedQueues ยังแสดง item เดิมระหว่างรอ fetch
    resizingQueue.value = null;
    resizeDirection.value = null;

    document.removeEventListener('mousemove', onResizing);
    document.removeEventListener('mouseup', onResizeEnd);
  }
}






// Pagination Functions
async function addPage() {
  if (pageStore.pages.length < 10) {
    await pageStore.addPage();
    await pageStore.fetchPages(); // 👈 โหลดหน้าทั้งหมดใหม่
  } else {
    alert('Maximum of 10 pages allowed.');
  }
}
function onPageRightClick(page: number, event: MouseEvent) {
  event.preventDefault();
  pageToShowDelete.value = page;
}


async function deletePage(pageNum: number) {
  await pageStore.removePage(pageNum);
  await pageStore.fetchPages(); // 👈 โหลดหน้าทั้งหมดใหม่

  if (currentPage.value === pageNum) {
    const remaining = pageStore.pages.map(p => p.pagenum);
    currentPage.value = remaining.length > 0 ? remaining[0] : 1;
  }
  pageToShowDelete.value = null;
}

function onDocumentClick(event: MouseEvent) {
  const target = event.target as HTMLElement;
  if (!target.closest('.page-btn')) {
    pageToShowDelete.value = null;
  }
}
onMounted(() => {
  document.addEventListener('click', onDocumentClick);
});
onBeforeUnmount(() => {
  document.removeEventListener('click', onDocumentClick);
});
</script>