import ProofingContext from "../../contexts/ProofingContext";

import {
    getThumb,
    isTouchScreen,
    useHandleListingResize,
} from "../../includes/functions";

const {useState, useEffect, useRef, useCallback, useContext} = React;
const {Button} = wp.components;

export default function Body() {

    const context = useContext(ProofingContext);
    const {
        submission,
        selectedTags,
    } = context;

    const {files = []} = submission || {};

    const [selectedFiles, setSelectedFiles] = useState([]);

    const initialView = localStorage.getItem('igd_selections_view') || 'grid';
    const [view, setView] = useState(initialView);
    const [filteredFiles, setFilteredFiles] = useState(files);


    /* -----------------------------
     * Handlers
     * --------------------------- */
    const toggleView = useCallback(() => {
        const nextView = view === 'grid' ? 'list' : 'grid';
        setView(nextView);
        localStorage.setItem('igd_selections_view', nextView);
    }, [view]);

    const clearSelections = useCallback(() => {
        setSelectedFiles([]);
        requestAnimationFrame(() => {
            containerRef.current
                ?.querySelectorAll('.selection-item.active')
                .forEach(el => el.classList.remove('active'));
        });
    }, []);

    const toggleFileSelection = useCallback((file) => {

        setSelectedFiles(prev => {

            const exists = prev.find(f => f.id === file.id && f?.user?.email === file.user?.email);

            return exists
                ? prev.filter(f => f.id !== file.id || f?.user?.email !== file.user?.email)
                : [...prev, file];
        });

    }, []);

    /* -----------------------------
     * CSV Export
     * --------------------------- */
    const downloadSelectedFilesAsCSV = useCallback((files = []) => {
        if (!files.length) return;

        const headers = ['ID', 'Name', 'Description', 'Tag', 'URL'];

        const rows = files.map(file => [
            `"${file.id || ''}"`,
            `"${file.name || ''}"`,
            `"${(file.description || '').replace(/"/g, '""')}"`,
            `"${file.reviewTag?.label || ''}"`,
            `"${file.webViewLink || ''}"`,
        ]);

        const csv = [headers, ...rows].map(r => r.join(',')).join('\n');

        const blob = new Blob([csv], {type: 'text/csv;charset=utf-8;'});
        const url = URL.createObjectURL(blob);

        const a = document.createElement('a');
        a.href = url;
        a.download = `selected-files-${Date.now()}.csv`;
        a.click();

        URL.revokeObjectURL(url);
    }, []);

    /* -----------------------------
     * Drag Select Logic
     * --------------------------- */
    const containerRef = useRef(null);
    const isDraggingRef = useRef(false);
    const suppressClickRef = useRef(false);


    useEffect(() => {
        if (isTouchScreen() || !files.length || !containerRef.current) return;

        const area = containerRef.current;
        const dragThreshold = 5;

        const selectionRect = document.createElement('div');
        selectionRect.className = 'igd-selection-rect';
        selectionRect.style.cssText = `
        position:absolute;
        display:none;
        pointer-events:none;
    `;
        area.appendChild(selectionRect);

        let startX = 0;
        let startY = 0;
        let isDragging = false;
        let rafId = null;

        const getAreaCoords = (clientX, clientY) => {
            const r = area.getBoundingClientRect();
            return {
                x: clientX - r.left + area.scrollLeft,
                y: clientY - r.top + area.scrollTop,
            };
        };

        const normalizeRect = (x1, y1, x2, y2) => {
            const left = Math.min(x1, x2);
            const top = Math.min(y1, y2);
            const right = Math.max(x1, x2);
            const bottom = Math.max(y1, y2);
            return {left, top, right, bottom};
        };

        const rectsOverlap = (a, b) =>
            !(a.right < b.left || a.left > b.right || a.bottom < b.top || a.top > b.bottom);

        const onMouseDown = (e) => {
            if (e.button !== 0) return;

            e.preventDefault();

            suppressClickRef.current = false;
            isDraggingRef.current = false;
            isDragging = false;

            const {x, y} = getAreaCoords(e.clientX, e.clientY);
            startX = x;
            startY = y;

            selectionRect.style.display = 'none';
            selectionRect.style.left = `${x}px`;
            selectionRect.style.top = `${y}px`;
            selectionRect.style.width = '0px';
            selectionRect.style.height = '0px';

            document.body.classList.add('igd-noselect');

            window.addEventListener('mousemove', onMouseMove);
            window.addEventListener('mouseup', onMouseUp);
        };

        const onMouseMove = (e) => {
            e.preventDefault();

            const {x, y} = getAreaCoords(e.clientX, e.clientY);

            if (!isDragging) {
                if (
                    Math.abs(x - startX) < dragThreshold &&
                    Math.abs(y - startY) < dragThreshold
                ) {
                    return;
                }

                isDragging = true;
                isDraggingRef.current = true;
                selectionRect.style.display = 'block';
            }

            const rect = normalizeRect(startX, startY, x, y);

            selectionRect.style.left = `${rect.left}px`;
            selectionRect.style.top = `${rect.top}px`;
            selectionRect.style.width = `${rect.right - rect.left}px`;
            selectionRect.style.height = `${rect.bottom - rect.top}px`;

            if (!rafId) {
                rafId = requestAnimationFrame(() => {
                    rafId = null;

                    const areaRect = area.getBoundingClientRect();

                    area.querySelectorAll('.selection-item').forEach(el => {
                        const r = el.getBoundingClientRect();

                        const itemRect = {
                            left: r.left - areaRect.left + area.scrollLeft,
                            top: r.top - areaRect.top + area.scrollTop,
                            right: r.right - areaRect.left + area.scrollLeft,
                            bottom: r.bottom - areaRect.top + area.scrollTop,
                        };

                        el.classList.toggle(
                            'igd-selecting',
                            rectsOverlap(rect, itemRect)
                        );
                    });
                });
            }
        };

        const onMouseUp = () => {
            window.removeEventListener('mousemove', onMouseMove);
            window.removeEventListener('mouseup', onMouseUp);
            document.body.classList.remove('igd-noselect');

            if (!isDraggingRef.current) {
                cleanup();
                return;
            }

            const selectionBox = {
                left: selectionRect.offsetLeft,
                top: selectionRect.offsetTop,
                right: selectionRect.offsetLeft + selectionRect.offsetWidth,
                bottom: selectionRect.offsetTop + selectionRect.offsetHeight,
            };

            const areaRect = area.getBoundingClientRect();
            const picked = [];

            area.querySelectorAll('.selection-item').forEach(el => {
                el.classList.remove('igd-selecting');

                const r = el.getBoundingClientRect();
                const itemRect = {
                    left: r.left - areaRect.left + area.scrollLeft,
                    top: r.top - areaRect.top + area.scrollTop,
                    right: r.right - areaRect.left + area.scrollLeft,
                    bottom: r.bottom - areaRect.top + area.scrollTop,
                };

                if (rectsOverlap(selectionBox, itemRect)) {
                    const id = el.getAttribute('data-id');

                    const file = files.find(f => f.id === id);

                    if (file) picked.push(file);
                }
            });

            if (picked.length) {
                setSelectedFiles(prev => {
                    const existing = new Set(
                        prev.map(f => `${f.id}|${f?.user?.email || ''}`)
                    );

                    const uniquePicked = picked.filter(p => {
                        const key = `${p.id}|${p?.user?.email || ''}`;
                        if (existing.has(key)) return false;
                        existing.add(key);
                        return true;
                    });

                    return [...prev, ...uniquePicked];
                });
            }


            suppressClickRef.current = true;
            requestAnimationFrame(() => {
                suppressClickRef.current = false;
                isDraggingRef.current = false;
            });

            cleanup();
        };

        const cleanup = () => {
            selectionRect.style.display = 'none';
            isDragging = false;
            if (rafId) {
                cancelAnimationFrame(rafId);
                rafId = null;
            }
        };

        area.addEventListener('mousedown', onMouseDown);

        return () => {
            area.removeEventListener('mousedown', onMouseDown);
            selectionRect.remove();
            document.body.classList.remove('igd-noselect');
            if (rafId) cancelAnimationFrame(rafId);
        };

    }, [filteredFiles]);

    const listClass = useHandleListingResize(containerRef, view === 'list');

    useEffect(() => {
        if (selectedTags.length === 0) {
            setFilteredFiles(files);
        } else {
            const filtered = files.filter(file =>
                selectedTags.includes(file.reviewTag?.value)
            );
            setFilteredFiles(filtered);
        }
    }, [selectedTags]);

    return (
        <div className="igd-proof-selections-body">

            <div className="body-header">
                <h3 className="body-title">
                    {wp.i18n.__('Files', 'integrate-google-drive')}
                </h3>

                <div className="body-actions">
                    {selectedFiles.length > 0 && (
                        <>
                            <div className="selected-files-count">
                                {wp.i18n.sprintf(
                                    wp.i18n._n(
                                        '%d item selected',
                                        '%d items selected',
                                        selectedFiles.length,
                                        'integrate-google-drive'
                                    ),
                                    selectedFiles.length
                                )}
                            </div>

                            <Button
                                icon="no-alt"
                                onClick={clearSelections}
                                label={wp.i18n.__('Clear selections', 'integrate-google-drive')}
                            />

                            <Button
                                icon="download"
                                onClick={() => downloadSelectedFilesAsCSV(selectedFiles)}
                                label={wp.i18n.__('Download selected as CSV', 'integrate-google-drive')}
                            />
                        </>
                    )}

                    <Button
                        icon={view === 'grid' ? 'list-view' : 'grid-view'}
                        onClick={toggleView}
                        label={
                            view === 'grid'
                                ? wp.i18n.__('Switch to list view', 'integrate-google-drive')
                                : wp.i18n.__('Switch to grid view', 'integrate-google-drive')
                        }
                    />
                </div>
            </div>

            <div className="body-content">
                <div
                    ref={containerRef}
                    className={`selections-list ${view}-view ${listClass}`}
                >
                    {filteredFiles.length ? (
                        filteredFiles.map(file => {
                            const isActive = selectedFiles.find(f => f.id === file.id);

                            return (
                                <div
                                    key={file.id}
                                    data-id={file.id}
                                    className={`selection-item ${isActive ? 'active' : ''}`}
                                    onClick={() => {
                                        if (suppressClickRef.current) return;

                                        window.open(file.webViewLink, '_blank')
                                    }}
                                >
                                    <div className="selection-item-thumbnail">
                                        <img
                                            src={getThumb(file, 'small', false, true)}
                                            alt={file.name}
                                            loading="lazy"
                                        />
                                    </div>

                                    <div className="selection-item-details">
                                        <div
                                            className={`selection-item-checkbox ${isActive ? 'checked' : ''}`}
                                            onClick={e => {
                                                e.stopPropagation();
                                                toggleFileSelection(file);
                                            }}
                                        />

                                        <h4>{file.name}</h4>
                                        {file.description && <p className={'description'}>{file.description}</p>}

                                        {file.reviewTag?.label && (
                                            <span
                                                className="selection-item-tag"
                                                style={{
                                                    backgroundColor: file.reviewTag.color || '#ddd',
                                                }}
                                            >
                                                {file.reviewTag.label}
                                            </span>
                                        )}
                                    </div>
                                </div>
                            );
                        })
                    ) : (
                        <p>{wp.i18n.__('No files found.', 'integrate-google-drive')}</p>
                    )}
                </div>
            </div>
        </div>
    );
}
