<template>
    <div class="container-xxl flex-grow-1 container-p-y">
        <div class="card app-calendar-wrapper">
            <div class="row g-0">
                <!-- Sidebar: 사이드바 영역 -->
                <div class="col-3 border-end text-center" id="app-calendar-sidebar">
                    <div>

                        <div class="card-body">
                            <HalfDayButtons
                            ref="halfDayButtonsRef"
                            @toggleHalfDay="toggleHalfDay"
                            @addVacationRequests="saveVacationChanges"
                            :isDisabled="!hasChanges"
                            :selectedDate="selectedDate"
                            />
                            <ProfileList
                            @profileClick="handleProfileClick"
                            :remainingVacationData="remainingVacationData"
                            />
                        </div>
                        <VacationModal
                        v-if="isModalOpen"
                        :isOpen="isModalOpen"
                        :myVacations="filteredMyVacations"
                        :receivedVacations="filteredReceivedVacations"
                        :userColors="userColors"
                        @close="isModalOpen = false"
                        />
                        <VacationGrantModal
                        v-if="isGrantModalOpen"
                        :isOpen="isGrantModalOpen"
                        :targetUser="selectedUser"
                        :remainingQuota="remainingVacationData[selectedUser?.MEMBERSEQ] || 0"
                        @close="isGrantModalOpen = false"
                        @updateVacation="fetchRemainingVacation"
                        />
                    </div>
                </div>

                <!-- Main Content: 캘린더 영역 -->
                <div class="col app-calendar-content">
                    <div class="card shadow-none border-0">
                        <div class="card-body" style="position: relative;">
                        <full-calendar
                            ref="fullCalendarRef"
                            :options="calendarOptions"
                            class="flatpickr-calendar-only"
                        />
                        <!-- 숨겨진 데이트피커 인풋 -->
                        <input
                            ref="calendarDatepicker"
                            type="text"
                            style="display: none; position: absolute;"
                        />
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
import { reactive, ref, onMounted, nextTick, computed, watch, onBeforeUnmount  } from "vue";
import axios from "@api";
import "bootstrap-icons/font/bootstrap-icons.css";
// 달력
import FullCalendar from "@fullcalendar/vue3";
import dayGridPlugin from "@fullcalendar/daygrid";
import interactionPlugin from "@fullcalendar/interaction";
// Flatpickr, MonthSelect
import flatpickr from "flatpickr";
import monthSelectPlugin from "flatpickr/dist/plugins/monthSelect/index";
import "flatpickr/dist/flatpickr.min.css";
import "flatpickr/dist/plugins/monthSelect/style.css";
// 컴포넌트
import HalfDayButtons from "@c/button/HalfDayButtons.vue";
import ProfileList from "@c/vacation/ProfileList.vue";
import VacationModal from "@c/modal/VacationModal.vue";
import VacationGrantModal from "@c/modal/VacationGrantModal.vue";
import { fetchHolidays } from "@c/calendar/holiday.js";
// 스토어
import { useUserStore } from "@s/userList";
import { useUserInfoStore } from "@s/useUserInfoStore";
import { useToastStore } from '@s/toastStore';
// 라우터
import { useRouter } from "vue-router";

const router = useRouter();
// 스토어
const toastStore = useToastStore();
const userStore = useUserInfoStore();
const userListStore = useUserStore();
// 프로필
const userList = ref([]);
const userColors = ref({});
// 휴가정보
const myVacations = ref([]);
const receivedVacations = ref([]);
const remainingVacationData = ref({});
// 모달상태
const isModalOpen = ref(false);
const isGrantModalOpen = ref(false);
// FullCalendar 및 이벤트 관련
const fullCalendarRef = ref(null);
const calendarEvents = ref([]);
const selectedDates = ref(new Map());

const halfDayType = ref(null);
const vacationCodeMap = ref({});
const holidayDates = ref(new Set());
const fetchedEvents = ref([]);
const halfDayButtonsRef = ref(null);
const selectedDate = ref(null);
const selectedUser = ref(null);
const lastRemainingYear = ref(new Date().getFullYear());
const lastRemainingMonth = ref(String(new Date().getMonth() + 1).padStart(2, "0"));
// 데이트피커 인풋 ref
const calendarDatepicker = ref(null);
let fpInstance = null;
/* 변경사항 여부 확인 */
const hasChanges = computed(() => {
    return (
        selectedDates.value.size > 0 ||
        myVacations.value.some(vac => selectedDates.value.has(vac.date.split("T")[0]))
    );
});

// 캘린더 이동 함수 (이전, 다음, 오늘)
const moveCalendar = async (value = 0) => {
    const calendarApi = fullCalendarRef.value?.getApi();

    if (value === 1) {
        calendarApi.prev();  // 이전 달로 이동
    } else if (value === 2) {
        calendarApi.next();  // 다음 달로 이동
    } else if (value === 3) {
        calendarApi.today();  // 오늘 날짜로 이동
    }
};

/* 캘린더 설정 */
// 풀 캘린더 옵션,이벤트
const calendarOptions = reactive({
    plugins: [dayGridPlugin, interactionPlugin],
    initialView: "dayGridMonth",
    headerToolbar: {
        left: "today",
        center: "title",
        right: "prev,next",
    },
    contentHeight:"auto",
    locale: "ko",
    selectable: false,
    dateClick: handleDateClick,
    datesSet: handleMonthChange,
    events: calendarEvents,
    customButtons: {
        prev: {
            text: 'PREV',
            click: () => moveCalendar(1),
        },
        today: {
            text: 'TODAY',
            click: () => moveCalendar(3),
        },
        next: {
            text: 'NEXT',
            click: () => moveCalendar(2),
        },
    },
});
// 캘린더 월 변경
function handleMonthChange(viewInfo) {
    const currentDate = viewInfo.view.currentStart;
    const year = currentDate.getFullYear();
    const month = String(currentDate.getMonth() + 1).padStart(2, "0");
    loadCalendarData(year, month);
}
// 캘린더 클릭
function handleDateClick(info) {
    if (!info.date || !info.dateStr) {
        return;
    }
    const clickedDateStr = info.dateStr;
    const clickedDate = info.date;
    const todayStr = new Date().toISOString().split("T")[0];
    const todayObj = new Date(todayStr);
    const oneWeekAgoObj = new Date(todayObj);
    oneWeekAgoObj.setDate(todayObj.getDate() - 8); // 오늘 기준 7일 전 날짜

    // 주말(토, 일) 또는 공휴일 또는 오늘 -7일 날짜 → 클릭 불가능
    if (
        clickedDate.getDay() === 0 || // 일요일
        clickedDate.getDay() === 6 || // 토요일
        holidayDates.value.has(clickedDateStr) || // 공휴일
        clickedDateStr <= oneWeekAgoObj.toISOString().split("T")[0] // 오늘 -7일 날짜 포함 과거 날짜 클릭 방지
    ) {
        return;
    }

    // 기존 값 확인
    const currentValue = selectedDates.value.get(clickedDateStr);

    const isMyVacation = myVacations.value.some(vac => vac.date.substring(0, 10) === clickedDateStr && !vac.receiverId);

    if (!selectedDates.value.has(clickedDateStr) && isMyVacation && halfDayType.value) {
        const existingVacation = myVacations.value.find(vac => vac.date.substring(0, 10) === clickedDateStr && !vac.receiverId);
        const selectedType =
            halfDayType.value === "AM" ? "700101" :
            halfDayType.value === "PM" ? "700102" : "700103";
        if (existingVacation.type === selectedType) {
            toastStore.onToast("이미 사용한 연차입니다.", "e");
            if (halfDayButtonsRef.value) {
                halfDayButtonsRef.value.resetHalfDay();
            }
            halfDayType.value = null;
            return;
        }
    }

    // 이미 활성화된 날짜를 한 번 더 클릭하면 비활성화
    if (currentValue && currentValue !== "delete") {
        selectedDates.value.delete(clickedDateStr);
        updateCalendarEvents();
        return;
    }

    // 버튼을 누르지 않았을 때 - 삭제 모드
    if (!halfDayType.value) {
        if (isMyVacation) {
            if (currentValue === "delete") {
                selectedDates.value.delete(clickedDateStr);
            } else {
                selectedDates.value.set(clickedDateStr, "delete");
            }
        } else {
            selectedDates.value.set(clickedDateStr, "700103");
        }
        updateCalendarEvents();
        return;
    }

    // 버튼을 눌렀을 때 - 기존 휴가 삭제 후 새로운 값 추가
    if (isMyVacation) {
        selectedDates.value.set(clickedDateStr, "delete");
    }

    const type = halfDayType.value === "AM" ? "700101" :
                 halfDayType.value === "PM" ? "700102" :
                 "700103"; // 풀연차

    selectedDates.value.set(clickedDateStr, type);

    // 버튼을 한 번 사용 후 자동 해제 (일회성)
    halfDayType.value = null;
    if (halfDayButtonsRef.value) {
        halfDayButtonsRef.value.resetHalfDay();
    }

    updateCalendarEvents();
}

function markClickableDates() {
    nextTick(() => {
        const todayStr = new Date().toISOString().split("T")[0]; // 오늘 날짜 (YYYY-MM-DD)
        const todayObj = new Date(todayStr);
        const oneWeekAgoObj = new Date(todayObj);
        oneWeekAgoObj.setDate(todayObj.getDate() - 8); // 오늘 기준 7일 전 날짜

        document.querySelectorAll(".fc-daygrid-day").forEach((cell) => {
            const dateStr = cell.getAttribute("data-date");
            if (!dateStr) return; // 날짜가 없으면 스킵

            const dateObj = new Date(dateStr);

            // 주말(토요일, 일요일) 또는 공휴일 또는 오늘 -7일 날짜 → 클릭 불가능
            if (
                dateObj.getDay() === 0 || // 일요일
                dateObj.getDay() === 6 || // 토요일
                holidayDates.value.has(dateStr) || // 공휴일
                dateObj.getTime() <= oneWeekAgoObj.getTime() // 오늘 -7일 날짜
            ) {
                cell.classList.remove("clickable");
                cell.classList.add("fc-day-sat-sun");
                cell.removeEventListener("click", handleDateClick); // 클릭 이벤트 제거
            }
            // 오늘 -6일부터 미래 날짜까지 클릭 가능
            else {
                cell.classList.add("clickable");
                cell.classList.remove("past", "fc-day-sat-sun");
                cell.addEventListener("click", handleDateClick); // 클릭 이벤트 추가
            }
        });
    });
}
//캘린더에 데이터 로드
async function loadCalendarData(year, month) {
    if (lastRemainingYear.value !== year || lastRemainingMonth.value !== month) {
        await fetchRemainingVacation();
        lastRemainingYear.value = year;
        lastRemainingMonth.value = month;
    }
    fetchedEvents.value = [];
    const [vacationEvents, holidayEvents] = await Promise.all([
        fetchVacationData(year, month),
        fetchHolidays(year, month),
    ]);
    holidayDates.value = new Set(holidayEvents.map((event) => event.start));
    fetchedEvents.value = [...vacationEvents, ...holidayEvents];
    updateCalendarEvents();
    await nextTick();
    fullCalendarRef.value.getApi().refetchEvents();
}

/* 프로필 구역 */
// 프로필 클릭 시 모달 열기
const handleProfileClick = async (user) => {
    try {
        if (isModalOpen.value && user.MEMBERSEQ === userStore.user.id) {
            return;
        }
        if (isGrantModalOpen.value && selectedUser.value?.MEMBERSEQ === user.MEMBERSEQ) {
            return;
        }
        isModalOpen.value = false;
        isGrantModalOpen.value = false;
        if (user.MEMBERSEQ === userStore.user.id) {
            const displayedYear = lastRemainingYear.value;
            await fetchVacationHistory(displayedYear);
            isModalOpen.value = true;
        } else {
            selectedUser.value = user;
            isGrantModalOpen.value = true;
        }
    } catch (error) {
    }
};
// 프로필 사원 리스트
const fetchUserList = async () => {
    try {
        await userListStore.fetchUserList();

        userList.value = [...userListStore.userList];

        if (!userList.value.length) {
            console.warn("📌 사용자 목록이 비어 있음!");
            return;
        }

        // 사용자별 색상 저장
        userColors.value = {};
        userList.value.forEach((user) => {
            userColors.value[user.MEMBERSEQ] = user.usercolor;
        });

    } catch (error) {
    }
};
// 사원별 남은 연차 개수
const fetchRemainingVacation = async () => {
    try {
        const response = await axios.get("vacation/remaining");
        if (response.status === 200) {
            remainingVacationData.value = response.data.data.reduce((acc, vacation) => {
                acc[vacation.employeeId] = vacation.remainingQuota;
                return acc;
            }, {});
        }
    } catch (error) {
    }
};
// 로그인한 사원이 사용한 휴가 필터링
const filteredMyVacations = computed(() => {
    return myVacations.value.filter(vac => {
        const dateStr = vac.date;
        const year = dateStr ? dateStr.split("T")[0].substring(0, 4) : null;
        return year === String(lastRemainingYear.value);
    });
});
// 로그인한 사원이 받은 휴가 필터링
const filteredReceivedVacations = computed(() => {
    return receivedVacations.value.filter(vac => {
        const dateStr = vac.date;
        const year = dateStr ? dateStr.split("T")[0].substring(0, 4) : null;
        return dateStr && year === String(lastRemainingYear.value);
    });
});

/* 휴가 저장 */
// 휴가 변경사항 저장
async function saveVacationChanges() {
    if (!hasChanges.value) return;

    const selectedDatesArray = Array.from(selectedDates.value);

    // 전체 연도를 고려하여 삭제 및 추가할 데이터를 분리
    const vacationChanges = selectedDatesArray.reduce((acc, [date, type]) => {
        if (type !== "delete") {
            acc.add.push({ date, type });
        } else {
            acc.delete.push(date);
        }
        return acc;
    }, { add: [], delete: [] });

    try {
        // 모든 연도의 데이터를 고려하여 삭제할 ID 찾기
        const allYears = new Set(vacationChanges.delete.map(date => date.split("-")[0]));
        let vacationIdsToDelete = [];
        for (const year of allYears) {
            await fetchVacationHistory(year);  // 각 연도의 최신 데이터를 가져오기
            const vacationsToDelete = myVacations.value.filter(vac => {
                if (!vac.date) return false;
                const vacDate = vac.date.split("T")[0];
                return vacationChanges.delete.includes(vacDate) && !vac.receiverId;
            });
            vacationIdsToDelete.push(...vacationsToDelete.map(vac => vac.id));
        }

        if (vacationChanges.add.length > 0 || vacationIdsToDelete.length > 0) {
            const response = await axios.post("vacation/batchUpdate", {
                add: vacationChanges.add,
                delete: vacationIdsToDelete,
            });
            if (response.data && response.data.status === "OK") {
                toastStore.onToast(`휴가 변경 사항이 저장되었습니다.`, 's');

                // 삭제된 ID를 반영하여 모든 연도의 `myVacations.value`를 업데이트
                myVacations.value = myVacations.value.filter(vac => !vacationIdsToDelete.includes(vac.id));

                // 삭제 후 최신 데이터 불러오기 (기존 데이터를 유지하면서 추가)
                const yearsToUpdate = new Set(
                    [...vacationChanges.add.map(v => v.date.split("-")[0]),
                        ...vacationChanges.delete.map(v => v.split("-")[0])]
                );

                for (const year of yearsToUpdate) {
                    const updatedVacations = await fetchVacationHistory(year);
                    if (updatedVacations) {
                        myVacations.value = [...myVacations.value, ...updatedVacations.filter(newVac =>
                            !myVacations.value.some(oldVac => oldVac.id === newVac.id)
                        )];
                    }
                }
            } else {
                toastStore.onToast(`휴가 변경 중 오류가 발생했습니다.`, 'e');
            }
        }
        await fetchRemainingVacation();
        selectedDates.value.clear();
        updateCalendarEvents();
        // 캘린더 새로고침
        const currentDate = fullCalendarRef.value.getApi().getDate();
        await loadCalendarData(currentDate.getFullYear(), currentDate.getMonth() + 1);
    } catch (error) {
        toastStore.onToast('휴가 저장 요청에 실패했습니다.', 'e');
    }
}
/* 휴가 조회 */
// 로그인 사용자의 연차 사용 내역
async function fetchVacationHistory(year) {
    try {
        const response = await axios.get(`vacation/history?year=${year}`);
        if (response.status === 200 && response.data) {
            myVacations.value = response.data.data.usedVacations || [];
            receivedVacations.value = response.data.data.receivedVacations || []
        }
    } catch (error) {
    }
}
// 모든 사원 연차 내역 및 그래프화
async function fetchVacationData(year, month) {
    try {
        const response = await axios.get(`vacation/list/${year}/${month}`);
        if (response.status === 200) {
            const vacationList = response.data;
            // 회원 정보가 없거나 색상 정보가 없는 데이터는 제외
            const filteredVacations = vacationList.filter(vac =>
                userColors.value[vac.MEMBERSEQ] && userColors.value[vac.MEMBERSEQ] && !vac.LOCVACRMM
            );
            const events = filteredVacations.map(vac => {
                let dateStr = vac.LOCVACUDT ? vac.LOCVACUDT.split("T")[0] : "";
                let backgroundColor = userColors.value[vac.MEMBERSEQ];
                return {
                    title: getVacationType(vac.LOCVACTYP),
                    start: dateStr,
                    backgroundColor,
                    classNames: [getVacationTypeClass(vac.LOCVACTYP)],
                    saved: true,
                    memberSeq: vac.MEMBERSEQ,
                };
            }).filter(event => event.start);
            return events;
        } else {
            console.warn("📌 휴가 데이터를 불러오지 못함");
            return [];
        }
        } catch (error) {
        return [];
    }
}
// 캘린더 이벤트 업데이트
function updateCalendarEvents() {
    const selectedEvents = Array.from(selectedDates.value)
        .filter(([date, type]) => type !== "delete")
        .map(([date, type]) => ({
            start: date,
            backgroundColor: "rgb(113 212 243 / 76%)", // 클릭하면 하늘색
            textColor: "#fff",
            display: "background",
            classNames: [getVacationTypeClass(type), "selected-event"] // 선택된 날짜 클래스 추가
        }));

    const filteredFetchedEvents = fetchedEvents.value.filter(event => {
        if (event.saved && selectedDates.value.get(event.start) === "delete") {
            if (event.memberSeq === userStore.user.id) {
                return false;
            }
        }
        return true;
    });

    calendarEvents.value = [...filteredFetchedEvents, ...selectedEvents];

    nextTick(() => {
        const todayStr = new Date().toISOString().split("T")[0];
        const todayElement = document.querySelector(`.fc-daygrid-day[data-date="${todayStr}"]`);

        if (todayElement) {
            // 오늘 날짜가 선택된 경우 배경 제거
            if (selectedDates.value.has(todayStr)) {
                todayElement.classList.remove("fc-day-today"); // 기본 스타일 제거
                todayElement.classList.add("selected-event"); // 선택된 날짜 스타일 적용

                // 🔹 오전 반차일 경우 'half-day-am' 클래스 추가
                if (selectedDates.value.get(todayStr) === "700101") {
                    todayElement.classList.add("half-day-am");
                    todayElement.classList.remove("half-day-pm");
                }
                // 🔹 오후 반차일 경우 'half-day-pm' 클래스 추가
                else if (selectedDates.value.get(todayStr) === "700102") {
                    todayElement.classList.add("half-day-pm");
                    todayElement.classList.remove("half-day-am");
                } else {
                    todayElement.classList.remove("half-day-am", "half-day-pm");
                }
            } else {
                todayElement.classList.add("fc-day-today"); // 기본 스타일 복원
                todayElement.classList.remove("selected-event", "half-day-am", "half-day-pm"); // 선택된 상태 해제
            }
        }
    });
}
// 휴가 종류에 따른 클래스명
const getVacationTypeClass = (type) => {
    if (type === "700101") return "half-day-am";
    if (type === "700102") return "half-day-pm";
    return "full-day";
};
// 휴가종류
const fetchVacationCodes = async () => {
    try {
        const response = await axios.get("vacation/codes");
        if (response.status === 200 && response.data) {
            vacationCodeMap.value = response.data.data.reduce((acc, item) => {
                acc[item.code] = item.name;
                return acc;
            }, {});
        } else {
            console.warn("❌ 공통 코드 데이터를 불러오지 못했습니다.");
        }
    } catch (error) {
    }
};
const getVacationType = (typeCode) => {
    return vacationCodeMap.value[typeCode] || "기타";
};

/* 버튼 */
// 반차버튼 토글
function toggleHalfDay(type) {
    halfDayType.value = halfDayType.value === type ? null : type;
}

/* 페이지 이동 시 변경 사항 확인 */
router.beforeEach((to, from, next) => {
    if (hasChanges.value) {
        const answer = window.confirm("저장하지 않은 변경 사항이 있습니다. 이동하시겠습니까?");
        if (!answer) {
            return next(false);
        }
    }
    selectedDates.value.clear();
    next();
});
onBeforeUnmount(() => {
    window.removeEventListener("beforeunload", preventUnsavedChanges);

});
/* 새로고침 또는 페이지 종료 시 알림 */
function preventUnsavedChanges(event) {
    if (hasChanges.value) {
        event.preventDefault();
        event.returnValue = "";
    }
}

/* watch */
watch(() => lastRemainingYear.value, async (newYear, oldYear) => {
    if (newYear !== oldYear) {
        await fetchVacationHistory(newYear);
    }
});
// 새로운 휴가추가 시 반차 버튼 초기화
watch(
    () => Array.from(selectedDates.value.keys()), // 선택된 날짜 리스트 감시
    (newKeys) => {
        if (halfDayButtonsRef.value && !halfDayType.value) {
            halfDayButtonsRef.value.resetHalfDay();
        }
    },
    { deep: true }
);
// selectedDates가 변경될 때 버튼 상태 즉시 업데이트
watch(
    () => Array.from(selectedDates.value.keys()),
    (newKeys) => {
    },
    { deep: true }
);
watch([holidayDates, lastRemainingYear, lastRemainingMonth], () => {
    markClickableDates();
});

/* onMounted */
// onMounted 및 달력 변경 시 실행
onMounted(() => {
    markClickableDates();
});
// onMounted 시 데이터 로드
onMounted(async () => {
    await userStore.userInfo();
    await fetchUserList();
    await fetchVacationCodes();
    const today = new Date();
    const year = today.getFullYear();
    const month = String(today.getMonth() + 1).padStart(2, "0");
    await fetchVacationData(year, month);
    await loadCalendarData(year, month);
    await fetchRemainingVacation();
    const currentYear = new Date().getFullYear();
    await fetchVacationHistory(currentYear);
    window.addEventListener("beforeunload", preventUnsavedChanges);
    // Flatpickr 초기화 (달 선택)
    fpInstance = flatpickr(calendarDatepicker.value, {
        dateFormat: "Y-m",
        plugins: [
            new monthSelectPlugin({
                shorthand: true,
                dateFormat: "Y-m",
                altFormat: "F Y"
            })
        ],
        onOpen: function() {
            document.querySelector('.flatpickr-input').style.visibility = 'hidden';
        },
        onChange: function(selectedDatesArr, dateStr) {
            // 선택한 달의 첫날로 달력을 이동
            fullCalendarRef.value.getApi().gotoDate(dateStr + "-01");
            const [year, month] = dateStr.split("-");
            lastRemainingYear.value = parseInt(year, 10);
            lastRemainingMonth.value = month;
            loadCalendarData(lastRemainingYear.value, lastRemainingMonth.value);
        },
        onClose: function() {
            calendarDatepicker.value.style.display = "none";
        }
    });
    // FullCalendar 년월월(.fc-toolbar-title) 클릭 시 데이트피커 열기
    nextTick(() => {
        const titleEl = document.querySelector('.fc-toolbar-title');
        if (titleEl) {
            titleEl.style.cursor = 'pointer';
            titleEl.addEventListener('click', () => {
                const dpEl = calendarDatepicker.value;
                dpEl.style.display = 'block';
                dpEl.style.position = 'fixed';
                dpEl.style.top = '18%';
                dpEl.style.left = '50%';
                dpEl.style.transform = 'translate(-50%, -50%)';
                dpEl.style.zIndex = '9999';
                dpEl.style.border = 'none';
                dpEl.style.outline = 'none';
                dpEl.style.backgroundColor = 'transparent';
                fpInstance.open();
            });
        }
    });
})
</script>
<style>
</style>
