import { useContext, useEffect, useRef, useState } from 'react';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import axios from 'axios';
import dayjs from 'dayjs';
import JSZip from 'jszip';
import AuthContext from "../../../../context/auth-context";
import useRole from "../../../../hooks/useRole";
import useLoading from "../../../../hooks/useLoading";
import {MonthDeltio, UserDeltia} from "../../../../models/HrSupport/PersonalFolder";
import {
    getLatestUpdateLabel, mapinitdAvailabYearsItem,
    mapSkonakiItem,
    mapToMonthDeltio,
    MAX_FILE_SIZE_BYTES,
    MONTHS_GR,
    YearOption
} from "./AenaTypes";
import {SkonakiData} from "../../../UI/Templates/SidebarSkonakiAena";
import {WithRuleBoolean} from "../../../HOC/WithRule";
import {getMyEmployeeOverview} from "../../../../API/hr_support";
import {getCollaborator} from "../../../../API/rescom";
import {
    deletea1Pdf,
    downloadLatestExcelA1,
    getDeltia, getInitdAvailabYearsData,
    getNavigatorYears,
    getSkonakiData, locka1Pdf, lockYear, sendAlfaEnaReminder,
    uploada1Pdf,
    uploadAlfaEnaFile,
    addSelectedYears,
} from "../../../../API/timesheets";
import {toastError, toastSuccess, toastWarn} from "../../../../services/toaster";
import {TriState} from "../../../UI/CustomToggler/CustomToggler";
import {encodeParams} from "../../../../helpers/encodedParams";
import {pusher} from "../../../../services/pusher";
import {InitedAvailabYearsData} from "./AenaHeader";

// ─── helpers (top of file, outside the hook) ───────────────────────────────

const renameFile = (file: File, newName: string): File =>
    new File([file], newName, { type: file.type, lastModified: file.lastModified });

const getFileExtension = (filename: string) => {
    const dot = filename.lastIndexOf('.');
    return dot !== -1 ? filename.slice(dot) : '';
};


export const useAenaData = () => {
    const navigate   = useNavigate();
    const { single } = useParams();
    const activeRole = useRole();
    const [searchParams, setSearchParams] = useSearchParams();

    const month   = Number(searchParams.get('month'));
    const urlYear = searchParams.get('year');

    const { globalSettings } = useContext(AuthContext);

    // ─── State ────────────────────────────────────────────────────────────────
    const [isLoading]                                 = useLoading(true);
    const [isAddingYears, setIsAddingYears] = useState(false);
    const [, setLoading]                              = useLoading(true);
    const [collaborator, setCollaborator]             = useState<any>(null);
    const [userDeltia, setUserDeltia]                 = useState<UserDeltia>([]);
    const [yearOptions, setYearOptions]               = useState<YearOption[]>([]);
    const [active, setActive]                         = useState('');
    const [locked, setLocked]                         = useState<boolean>(true);
    const [hasModal, setHasModal]                     = useState('');
    const [excelInfo, setExcelInfo]                   = useState<any>(null);
    const [templateInfo, setTemplateInfo]             = useState<any>(null);
    const [skonakiData, setSkonakiData]               = useState<SkonakiData[] | null>(null);
    const [initedAvailabYearsData, setInitedAvailabYearsData]               = useState<InitedAvailabYearsData[] | null>(null);
    const [latestUpdateOnPdfs, setLatestUpdateOnPdfs] = useState<string>('-');
    const [previewUrl, setPreviewUrl]                 = useState<string | null>(null);
    const [skonakiLoading, setSkonakiLoading]         = useState(false);
    const [initedAvailabYearsDataLoading, setInitedAvailabYearsDataLoading]         = useState(false);
    const [isZipping, setIsZipping]                   = useState(false);

    // ─── Derived ──────────────────────────────────────────────────────────────
    const employee         = collaborator;
    const canEdit          = activeRole !== 'dua_user';
    const canAddPeriod     = WithRuleBoolean('period', 'add');
    const canEditPeriod    = WithRuleBoolean('period', 'edit');
    const activeYear       = userDeltia.find(y => y.year === active);
    const latestExcelMonth = excelInfo?.A1_excel?.months?.length
        ? MONTHS_GR[Math.max(...excelInfo.A1_excel.months.map(Number)) - 1]
        : null;

    // ─── Side-effects ─────────────────────────────────────────────────────────

    useEffect(() => { setSkonakiData(null); }, [active]);

    useEffect(() => {
        (async () => {
            try {
                if (activeRole === 'dua_user') {
                    const { data } = await getMyEmployeeOverview(single);
                    setCollaborator(data);
                } else {
                    const resp = await getCollaborator(single ?? '');
                    setCollaborator(resp.data);
                }
            } catch (err) {
                console.error('Failed to fetch collaborator:', err);
                setCollaborator(null);
            }
        })();
    }, [single]);

    useEffect(() => {
        if (!collaborator) return;
        fetchYears();
    }, [collaborator]);

    useEffect(() => {
        if (!active) return;
        setExcelInfo(null);
        setLocked(true);
        fetchDeltia(active);
    }, [active]);

    // ─── Live lock updates ──────────────────────────────────────────────────────
    // The lock can flip server-side even when this viewer isn't the one who did it
    // (e.g. a supervisor downloads while the collaborator is on this same page).
    // Subscribe to the collaborator's personal channel and react instantly instead
    // of requiring a manual refresh.
    useEffect(() => {
        if (!pusher || !collaborator?.user?.dua_code || !active) return;

        const pusherClient = pusher; // narrow once, use this everywhere below
        const channelName = `user.${collaborator.user.dua_code}`;
        const channel = pusherClient.subscribe(channelName);


        const handleLockUpdate = (data: { year: string; locked: boolean }) => {
            if (String(data.year) === String(active)) {
                setLocked(data.locked);
            }
        };

        const handleFileUploaded = (data: { year: string }) => {
            if (String(data.year) === String(active)) {
                fetchDeltia(active); // refetch everything for this year: file, months, locked, deltia
            }
        };

        channel.bind('a1-lock-updated', handleLockUpdate);
        channel.bind('a1-file-uploaded', handleFileUploaded);
        channel.bind('a1-pdf-file-uploaded', handleFileUploaded);

        return () => {
            channel.unbind('a1-lock-updated', handleLockUpdate);
            channel.unbind('a1-pdf-file-uploaded', handleFileUploaded);
            pusherClient.unsubscribe(channelName);
        };
    }, [collaborator, active]);

    // ─── Data fetching ────────────────────────────────────────────────────────
    const abortControllerRef = useRef<AbortController | null>(null);

    const fetchYears = async () => {
        try {
            setLoading(true);
            const res     = await getNavigatorYears(collaborator.user.hash_id, activeRole);
            const years: YearOption[] = res.data.map((y: string) => ({ value: y, name: y }));
            setYearOptions(years);
            setUserDeltia(years.map(y => ({ year: y.value.toString(), deltia: [] })));
            const sorted       = [...years].sort((a, b) => Number(b.value) - Number(a.value));
            const currentYear  = dayjs().year().toString();
            const hasCurrent   = years.some(y => y.value.toString() === currentYear);
            const defaultYear  = hasCurrent ? currentYear : sorted[0]?.value?.toString() ?? currentYear;
            const initialYear  = urlYear ?? defaultYear;
            setActive(initialYear);
        } catch (err) {
            console.error('Failed to fetch years:', err);
        } finally {
            setLoading(false);
        }
    };

    const fetchDeltia = async (year: string) => {
        abortControllerRef.current?.abort();
        abortControllerRef.current = new AbortController();

        try {
            setLoading(true, true);
            const res          = await getDeltia(
                collaborator.user.hash_id,
                year,
                activeRole,
                abortControllerRef.current.signal,
            );
            const mappedDeltia = (res.data.a1_pdf_files ?? []).map(mapToMonthDeltio);

            setUserDeltia(prev =>
                prev.map(y => y.year === year ? { ...y, deltia: mappedDeltia } : y),
            );

            const excelData = res.data.a1_excel_file ?? null;
            setExcelInfo(excelData);
            setLocked(Boolean(excelData?.A1_excel?.locked ?? false));
            setTemplateInfo(res.data.template ?? null);
            setLatestUpdateOnPdfs(getLatestUpdateLabel(mappedDeltia));
        } catch (err) {
            if (axios.isCancel(err)) return;
        } finally {
            setLoading(false);
        }
    };

    const fetchSkonakiData = async () => {
        if (!active || !employee?.user?.id) return;
        try {
            setSkonakiLoading(true);
            const res = await getSkonakiData(active, employee.user.hash_id, activeRole);
            setSkonakiData((res.data.data ?? []).map(mapSkonakiItem));
        } catch (e: any) {
            console.warn('getSkonakiData failed (status:', e?.response?.status, ')');
            setSkonakiData([]);
        } finally {
            setSkonakiLoading(false);
        }
    };
    const fetchInitedAndAvailableYears = async () => {
        if (!active || !employee?.user?.id) return;
        try {
            setInitedAvailabYearsDataLoading(true);
            const res = await getInitdAvailabYearsData(employee.user.hash_id, activeRole);
            setInitedAvailabYearsData((res.data.data ?? []).map(mapinitdAvailabYearsItem));
        } catch (e: any) {
            console.warn('get initdAvailabYearsData failed (status:', e?.response?.status, ')');
            setInitedAvailabYearsData([]);
        } finally {
            setInitedAvailabYearsDataLoading(false);
        }
    };

    // ─── Shared blob fetcher ───────────────────────────────────────────────────
    // Both the excel and the month PDFs are served by the same endpoint.
    // This private helper returns a raw Blob so callers can do what they like
    // with it (trigger a download or add it to a ZIP).
    const getA1Blob = async (filepath: string, file_category_id: string | number): Promise<Blob> => {
        const form = new FormData();
        form.append('filepath',         filepath);
        form.append('file_category_id', String(file_category_id));
        form.append('hash_id',          employee.user.hash_id.toString());
        form.append('active_role',      activeRole);
        const response = await downloadLatestExcelA1(form);
        return new Blob([response.data]);
    };

    // ─── Handlers ─────────────────────────────────────────────────────────────


    const handleSendReminder = async (userId: number | string = -1, month:number, year:number) => {
        try {
            setLoading(true);
            await sendAlfaEnaReminder(userId, activeRole, month, year);
            toastSuccess(
                userId === -1
                    ? 'Η υπενθύμιση στάλθηκε σε όλους τους συνεργάτες που δεν έχουν υποβάλει.'
                    : 'Η υπενθύμιση στάλθηκε με επιτυχία.'
            );
        } catch (e: any) {
            toastError(e?.response?.data?.message ?? 'Κάτι πήγε στραβά κατά την αποστολή.');
        } finally {
            setLoading(false);
        }
    };

    const handleDeltioUpload = async (year: string, month: MonthDeltio, file: any) => {
        try {
            setLoading(true);
            const form = new FormData();
            form.append('hash_id',     employee.user.hash_id.toString());
            form.append('month',       month.monthI.toString());
            form.append('year',        year);
            form.append('active_role', activeRole);
            form.append('file[]',      file);
            await uploada1Pdf(form);
            await fetchDeltia(active);
            toastSuccess('To Aρχείο Pdf έχει υποβληθεί επιτυχώς.');
            return true;
        }catch (e: any) {
            if (e.response?.data?.message) toastWarn(e.response.data.message);
            else toastError('Κάτι πήγε στραβά κατά την υποβολή.');
            return false;}
        finally {
            setLoading(false);
        }
    };

    const handleFileUpload = async (data: any) => {
        try {
            if (data.file && data.file.size > MAX_FILE_SIZE_BYTES) {
                toastWarn('Πολύ μεγάλο μέγεθος αρχείου.');
                return false;
            }
            const form = new FormData();
            form.append('hash_id', data.user_hash_id);
            form.append('year', data.year);
            form.append('active_role', activeRole);
            data.selectedMonths.forEach((m: number) => form.append('months[]', m.toString()));

            if (data.file) {
                // Same logic as latestExcelMonth: take the highest selected month
                const latestMonthLabel = data.selectedMonths.length
                    ? MONTHS_GR[Math.max(...data.selectedMonths.map(Number)) - 1]
                    : null;

                const newName = `${employee.user.firstname}_${employee.user.lastname}_${data.year}${latestMonthLabel ? `_${latestMonthLabel}` : ''}${getFileExtension(data.file.name)}`;

                const renamedFile = renameFile(data.file, newName);
                form.append('file[]', renamedFile);
            }
            if (excelInfo?.A1_excel?.file?.uuid) form.append('uuid', excelInfo.A1_excel.file.uuid);

            await uploadAlfaEnaFile(form);
            await fetchDeltia(active);
            toastSuccess('To Aρχείο Excel έχει υποβληθεί επιτυχώς.');
            return true;
        } catch (e: any) {
            if (e.response?.data?.message) toastWarn(e.response.data.message);
            else toastError('Κάτι πήγε στραβά κατά την υποβολή.');
            return false;
        } finally {
            setLoading(false);
            setHasModal('');
        }
    };

    const handleAddSelectedYears = async (selectedYears: string[]) => {
        if (!selectedYears.length || !employee?.user?.hash_id) return false;
        try {
            setLoading(true);
            setIsAddingYears(true);
            await addSelectedYears({
                active_role: activeRole,
                hash_id: employee.user.hash_id,
                years: selectedYears,
            });
            toastSuccess('Η Αρχικοποίηση των επιλεγμένων ετών, ολοκληρώθηκε με επιτυχία!');
            await fetchYears(); // refetches yearOptions + userDeltia -> updates YearNavigator
            await fetchDeltia(active);
            return true;
        } catch (e: any) {
            if (e.response?.data?.message) toastWarn(e.response.data.message);
            else toastError('Κάτι πήγε στραβά κατά την προσθήκη ετών.');
            return false;
        } finally {
            setIsAddingYears(false);
            setLoading(false);
        }
    };

    const handleLatestDownload = async () => {
        try {
            setLoading(true);
            const blob = await getA1Blob(
                excelInfo?.A1_excel.file.filepath,
                excelInfo?.A1_excel.file.file_category_id,
            );
            const url  = window.URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.href  = url;
            link.setAttribute(
                'download',
                `${employee.user.firstname}_${employee.user.lastname}_${active}${latestExcelMonth ? `_${latestExcelMonth}` : ''}_timesheet.xlsx`,
            );
            document.body.appendChild(link);
            link.click();
            link.remove();
            window.URL.revokeObjectURL(url);
            toastSuccess('Το αρχείο κατέβηκε επιτυχώς.');
        } catch (e: any) {
            if (e.response?.data?.message) toastWarn(e.response.data.message);
            else toastError('Κάτι πήγε στραβά κατά την υποβολή.');
        } finally {
            const supervisorRoles = ['scientific_supervisor', 'project_manager', 'supervisor_elke'];
            if (supervisorRoles.includes(activeRole)) await handleToggleLocked(true);
            setLoading(false);
        }
    };

    const handleMonthPdfDownload = async (monthDeltio: MonthDeltio) => {
        const file = monthDeltio?.file as any;
        if (!file) return;

        try {
            setLoading(true);
            const blob = await getA1Blob(file.filepath, file.file_category_id);
            const url  = window.URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.href  = url;
            link.setAttribute(
                'download',
                `${employee.user.firstname}_${employee.user.lastname}_${active}_${monthDeltio.month}_timesheet.pdf`,
            );
            document.body.appendChild(link);
            link.click();
            link.remove();
            window.URL.revokeObjectURL(url);
            toastSuccess('To Μηνιαίο Δελτίο Κίνησης έχει κατέβει επιτυχώς.');
        } catch (e: any) {
            if (e.response?.data?.message) toastWarn(e.response.data.message);
            else toastError('Κάτι πήγε στραβά κατά την κατέβασμα.');
        } finally {
            setLoading(false);
        }
    };

    // ─── Bulk ZIP: excel + all month PDFs for the active year ─────────────────
    // Downloads each file sequentially (to avoid hammering the server), packs
    // them into a single ZIP, and triggers one browser download.
    const handleBulkDownloadYearZip = async () => {
        if (!activeYear) return;

        setIsZipping(true);
        try {
            const zip  = new JSZip();
            const base = `${employee.user.firstname}_${employee.user.lastname}_${active}`;

            // ── Excel ──
            const excelFile = excelInfo?.A1_excel?.file;
            if (excelFile?.filepath) {
                try {
                    const blob     = await getA1Blob(excelFile.filepath, excelFile.file_category_id);
                    const filename = `${base}${latestExcelMonth ? `_${latestExcelMonth}` : ''}_timesheet.xlsx`;
                    zip.file(filename, blob);
                } catch (err) {
                    console.error('ZIP: failed to fetch excel', err);
                }
            }

            // ── Month PDFs ──
            for (const deltio of activeYear.deltia) {
                const file = deltio?.file as any;
                if (!file?.filepath) continue;
                try {
                    const blob     = await getA1Blob(file.filepath, file.file_category_id);
                    const filename = `${base}_${deltio.month}_timesheet.pdf`;
                    zip.file(filename, blob);
                } catch (err) {
                    console.error(`ZIP: failed to fetch PDF for ${deltio.month}`, err);
                }
            }

            const zipBlob = await zip.generateAsync({ type: 'blob' });
            const url     = window.URL.createObjectURL(zipBlob);
            const link    = document.createElement('a');
            link.href     = url;
            link.download = `${base}_timesheet_package.zip`;
            document.body.appendChild(link);
            link.click();
            link.remove();
            window.URL.revokeObjectURL(url);
            toastSuccess('Το ZIP κατέβηκε επιτυχώς.');
        } catch (e: any) {
            toastError('Κάτι πήγε στραβά κατά τη δημιουργία του ZIP.');
        } finally {
            setIsZipping(false);
        }
    };

    const handleDeltioDelete = async (file_uuid: string) => {
        try {
            setLoading(true);
            await deletea1Pdf(file_uuid);
            await fetchDeltia(active);
        } catch (error) {
            console.error('Failed to delete PDF:', error);
        } finally {
            setLoading(false);
        }
    };

    const handleFileLock = async (year: string, monthI: number, isLocked: boolean) => {
        try {
            setLoading(true);
            await locka1Pdf(employee.user.hash_id, year, monthI, activeRole, !isLocked);
            await fetchDeltia(active);
        } catch (e: any) {
            if (e.response?.data?.message) toastWarn(e.response.data.message);
            else toastError('Κάτι πήγε στραβά');
        } finally {
            setLoading(false);
        }
    };

    const handleToggleLocked = async (value: TriState) => {
        const newLocked = Boolean(value);
        setLocked(newLocked);
        try {
            setLoading(true);
            await lockYear(active, newLocked, employee.user.hash_id, activeRole);
        } catch (error: any) {
            console.error('Error updating lock state:', error);
            toastError(error?.response?.data?.message ?? 'Κάτι πήγε στραβά');
            setLocked(!newLocked);
        } finally {
            setLoading(false);
        }
    };

    const handleOpenUploadModal = () => {
        if (locked && activeRole === 'dua_user') return;
        setHasModal('upload');
        setSearchParams(prev => {
            const p = new URLSearchParams(prev.toString());
            p.set('hasModal', 'upload');
            p.set('year', active);
            return p;
        });
    };

    const handleSetActive = (year: string) => {
        setActive(year);
        setSearchParams(prev => { prev.set('year', year); return prev; });
    };

    const handleEditYear = (year: string) => {
        if (canEditPeriod) {
            navigate(`edit/${year}?t=${encodeParams({ activeRole: activeRole ?? '' })}`);
        } else {
            setHasModal('');
        }
    };

    const closePreviewModal = () => setPreviewUrl(null);
    const closeUploadModal  = () => {
        setHasModal('');
        setSearchParams(prev => {
            const p = new URLSearchParams(prev.toString());
            p.delete('hasModal');
            p.delete('month');
            return p;
        });
    };



    // ─── Available months for the upload modal ────────────────────────────────
    const availableMonths = (() => {
        const allMonths  = excelInfo?.months?.map(Number) ?? [];
        const currentYear = new Date().getFullYear().toString();

        if (active !== currentYear) return allMonths;

        // const today      = new Date();
        // const cutoffMonth = today.getDate() >= 25
        //     ? today.getMonth() + 1
        //     : today.getMonth() + 1;

        return allMonths
            // .filter((m: number) => m <= cutoffMonth)
            ;
    })();

    return {
        // params / context
        single,
        activeRole,
        month,
        globalSettings,
        // state
        isLoading,
        collaborator,
        userDeltia,
        yearOptions,
        active,
        locked,
        hasModal,
        excelInfo,
        templateInfo,
        skonakiData,
        skonakiLoading,
        initedAvailabYearsData,
        initedAvailabYearsDataLoading,
        isAddingYears,
        latestUpdateOnPdfs,
        previewUrl,
        setPreviewUrl,
        isZipping,
        // derived
        employee,
        canEdit,
        canAddPeriod,
        canEditPeriod,
        activeYear,
        latestExcelMonth,
        availableMonths,
        // handlers
        fetchSkonakiData,
        fetchInitedAndAvailableYears,
        handleDeltioUpload,
        handleFileUpload,
        handleLatestDownload,
        handleMonthPdfDownload,
        handleBulkDownloadYearZip,
        handleDeltioDelete,
        handleFileLock,
        handleToggleLocked,
        handleOpenUploadModal,
        handleSetActive,
        handleEditYear,
        handleAddSelectedYears,
        handleSendReminder,
        closePreviewModal,
        closeUploadModal,
    };
};
