/**
 * KooKoa Folders — Item Drag & Drop + Metadata Tooltip
 *
 * Extracted from admin.js (block 12).
 * Adds methods to FO: initDragDrop, _initRowDraggable, _makeListRowsDraggable, _makeTreeNodesDroppable
 * Includes metadata tooltip IIFE for media grid hover.
 *
 * @since 1.0.0
 */
(function($) {
    'use strict';

    const FO = window.KookoaWPF;
    if (!FO) return;

    // ========================
    // Item Drag & Drop (posts/media → tree nodes)
    // ========================

    /**
     * Create a drag helper element showing thumbnail + count badge.
     *
     * @param {jQuery}  $el    The dragged element.
     * @param {jQuery=} $scope Scope to find selected items (defaults to document).
     * @return {jQuery} The helper element.
     */
    FO._createDragHelper = function($el, $scope) {
        const $container = $scope || $(document);
        const sel = $container.find('.attachment[aria-checked="true"], .attachment.selected');
        const count = sel.length > 1 ? sel.length : 1;
        let title = $el.find('.filename').text() || $el.find('.row-title, .title').first().text() || 'File';
        if (title.length > 20) title = title.substring(0, 20) + '…';

        const thumbSrc = $el.find('.thumbnail img, img.wp-post-image, td.column-icon img').first().attr('src') || '';
        const $helper = $('<div class="kookoawpf-drag-helper">');

        if (thumbSrc) {
            $helper.append($('<img class="kookoawpf-drag-thumb">').attr('src', thumbSrc));
        } else {
            $helper.append('<span class="dashicons dashicons-media-default"></span>');
        }

        $helper.append($('<span class="kookoawpf-drag-label">').text(count > 1 ? count + ' items' : title));

        if (count > 1) {
            $helper.append($('<span class="kookoawpf-drag-badge">').text(count));
        }

        return $helper;
    };

    FO.initDragDrop = function() {
        const self = this;
        // No drag & drop in trash view
        if (window.location.search.indexOf('post_status=trash') !== -1 || $('.subsubsub .trash.current').length) return;
        let _dragActive = false;
        let _lastHoverId = null;

        // Store drag state refs so _makeListRowsDraggable can access them
        self._dragState = { getActive: function() { return _dragActive; }, setActive: function(v) { _dragActive = v; }, resetHover: function() { _lastHoverId = null; } };

        // Make list rows draggable (delegated + explicit init, skip on mobile)
        $(document).on('mouseenter', '.wp-list-table tbody tr', function() {
            if ($('body').hasClass('kookoawpf-mobile')) return;
            self._initRowDraggable($(this));
        });
        self._makeListRowsDraggable();

        // Make grid attachments draggable (skip on mobile — touch conflicts with scroll)
        $(document).on('mouseenter', '.attachments-browser .attachment', function() {
            if ($('body').hasClass('kookoawpf-mobile')) return;
            const $att = $(this);
            if ($att.data('fo-d')) return;
            $att.data('fo-d', true);

            $att.draggable({
                helper: function() {
                    return FO._createDragHelper($(this));
                },
                appendTo: 'body', cursor: 'move',
                cursorAt: { left: 10, top: 10 }, distance: 10,
                revert: 'invalid', zIndex: 999999,
                start: function() {
                    // Smart folders are virtual: items inside them aren't real assignments,
                    // so dragging them anywhere would mislead the user.
                    if (FO.isCurrentFolderSmart && FO.isCurrentFolderSmart()) return false;
                    _dragActive = true;
                    $('body').addClass('kookoawpf-dragging');
                },
                stop: function() { _dragActive = false; _lastHoverId = null; $('body').removeClass('kookoawpf-dragging'); $('#kookoawpf-jstree .kookoawpf-drop-hover').removeClass('kookoawpf-drop-hover'); }
            });
        });

        // ── Metadata tooltip on media grid hover ──
        (function() {
            let _metaTipTimer = null;
            let _$metaTip = null;

            function _ensureMetaTip() {
                if (!_$metaTip || !_$metaTip.length) {
                    _$metaTip = $('<div id="kookoawpf-metadata-tooltip" class="kookoawpf-metadata-tooltip"></div>').hide().appendTo('body');
                }
                return _$metaTip;
            }

            function _formatMime(mime) {
                if (!mime || mime.indexOf('/') === -1) return mime || '—';

                // Full MIME match first — covers Office / Open XML long types.
                const fullMap = {
                    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':          'XLSX',
                    'application/vnd.openxmlformats-officedocument.wordprocessingml.document':    'DOCX',
                    'application/vnd.openxmlformats-officedocument.presentationml.presentation':  'PPTX',
                    'application/vnd.ms-excel':                        'XLS',
                    'application/msword':                              'DOC',
                    'application/vnd.ms-powerpoint':                   'PPT',
                    'application/vnd.oasis.opendocument.text':         'ODT',
                    'application/vnd.oasis.opendocument.spreadsheet':  'ODS',
                    'application/vnd.oasis.opendocument.presentation': 'ODP'
                };
                if (fullMap[mime]) return fullMap[mime];

                // Sub-type fallback (strip vnd./x- prefixes).
                let sub = mime.split('/')[1] || '';
                sub = sub.replace(/^(vnd\.|x-)/, '');
                const map = {
                    'jpeg':     'JPEG',
                    'jpg':      'JPEG',
                    'png':      'PNG',
                    'gif':      'GIF',
                    'webp':     'WebP',
                    'avif':     'AVIF',
                    'svg+xml':  'SVG',
                    'bmp':      'BMP',
                    'pdf':      'PDF',
                    'zip':      'ZIP',
                    'mp4':      'MP4',
                    'quicktime': 'MOV',
                    'mpeg':     'MPEG',
                    'mp3':      'MP3'
                };
                if (map[sub]) return map[sub];

                if (sub.length <= 4) return sub.toUpperCase();
                return sub.charAt(0).toUpperCase() + sub.slice(1);
            }

            function _formatSize(bytes) {
                bytes = parseFloat(bytes);
                if (!bytes || !isFinite(bytes) || bytes <= 0) return '—';
                if (bytes < 1024) return Math.round(bytes) + ' B';
                if (bytes < 1048576) return (bytes / 1024).toFixed(1).replace(/\.0$/, '') + ' KB';
                return (bytes / 1048576).toFixed(1).replace(/\.0$/, '') + ' MB';
            }

            function _formatAperture(apert) {
                if (!apert && apert !== 0) return '';
                const a = parseFloat(apert);
                if (!isFinite(a) || a <= 0) return String(apert);
                return 'f/' + (a < 10 ? a.toFixed(1).replace(/\.0$/, '') : Math.round(a));
            }

            function _formatShutter(sec) {
                if (!sec && sec !== 0) return '';
                const s = parseFloat(sec);
                if (!isFinite(s) || s <= 0) return String(sec);
                if (s >= 1) return s.toFixed(1).replace(/\.0$/, '') + 's';
                return '1/' + Math.round(1 / s) + 's';
            }

            function _formatFocal(focal) {
                if (!focal && focal !== 0) return '';
                const f = parseFloat(focal);
                if (!isFinite(f) || f <= 0) return String(focal);
                return Math.round(f) + 'mm';
            }

            let _metaMouseX = 0, _metaMouseY = 0;

            function _showMetaTip($att, att) {
                const $tip = _ensureMetaTip();
                const w = att.get('width');
                const h = att.get('height');
                const size = att.get('filesizeInBytes') || att.get('filesize');
                const mime = att.get('mime') || att.get('type');
                const dateStr = att.get('dateFormatted') || att.get('date') || '';

                // Build tooltip using jQuery DOM methods to prevent XSS
                const strings = self.data.strings || {};
                const $title = $('<div class="kookoawpf-meta-title">').text(strings.metaFileInfo);
                const $table = $('<table class="kookoawpf-meta-table">');
                function _addRow(label, value) {
                    $table.append(
                        $('<tr>').append(
                            $('<td class="kookoawpf-meta-label">').text(label),
                            $('<td class="kookoawpf-meta-value">').text(value)
                        )
                    );
                }
                if (w && h) {
                    _addRow(strings.metaSize, w + ' × ' + h + ' px');
                }
                _addRow(strings.metaWeight, _formatSize(size));
                _addRow(strings.metaFormat, _formatMime(mime));
                if (dateStr) {
                    // Clean WP date format — show only date part
                    let clean = dateStr.replace(/<[^>]+>/g, '').trim();
                    if (!clean && att.get('date')) {
                        const d = new Date(att.get('date'));
                        if (!isNaN(d)) {
                            clean = d.toLocaleDateString();
                        }
                    }
                    if (clean) {
                        _addRow(strings.metaDate, clean);
                    }
                }

                $tip.empty().append($title).append($table);

                // ── EXIF Info block (optional, photographer mode) ──
                const exif = att.get('kookoawpfExif');
                if (self.data.showExif && exif && typeof exif === 'object') {
                    const $exifTitle = $('<div class="kookoawpf-meta-title kookoawpf-meta-title-exif">').text(strings.metaExifInfo);
                    const $exifTable = $('<table class="kookoawpf-meta-table">');
                    function _addExifRow(label, value) {
                        if (!value) return;
                        $exifTable.append(
                            $('<tr>').append(
                                $('<td class="kookoawpf-meta-label">').text(label),
                                $('<td class="kookoawpf-meta-value">').text(value)
                            )
                        );
                    }
                    _addExifRow(strings.metaCamera, exif.camera || '');
                    _addExifRow(strings.metaAperture, _formatAperture(exif.aperture));
                    _addExifRow(strings.metaShutter, _formatShutter(exif.shutter));
                    _addExifRow(strings.metaIso, exif.iso || '');
                    _addExifRow(strings.metaFocal, _formatFocal(exif.focal));
                    if ($exifTable.children().length > 0) {
                        $tip.append($exifTitle).append($exifTable);
                    }
                }

                $tip.show();

                // Position — above and left of cursor
                const tipW = $tip.outerWidth();
                const tipH = $tip.outerHeight();
                const scrollTop = $(window).scrollTop();
                let left = _metaMouseX - tipW - 15;
                let top = _metaMouseY + scrollTop - tipH - 15;

                if (left < 10) left = _metaMouseX + 15;
                if (top < scrollTop + 10) top = _metaMouseY + scrollTop + 15;

                $tip.css({ top: top, left: left });
            }

            $(document).on('mousemove', '.attachments-browser .attachment', function(e) {
                _metaMouseX = e.clientX;
                _metaMouseY = e.clientY;
            });

            $(document).on('mouseenter', '.attachments-browser .attachment', function(e) {
                if (!self.data.showMetadataTooltip) return;
                if (_dragActive) return;
                _metaMouseX = e.clientX;
                _metaMouseY = e.clientY;

                const $att = $(this);
                const id = $att.data('id');
                if (!id || !wp.media || !wp.media.attachment) return;

                clearTimeout(_metaTipTimer);
                _metaTipTimer = setTimeout(function() {
                    const att = wp.media.attachment(id);
                    if (!att || !att.get('mime')) {
                        att.fetch().done(function() {
                            if ($att.is(':hover')) _showMetaTip($att, att);
                        });
                    } else {
                        _showMetaTip($att, att);
                    }
                }, 500);
            });

            $(document).on('mouseleave', '.attachments-browser .attachment', function() {
                clearTimeout(_metaTipTimer);
                _ensureMetaTip().hide();
            });

            // Hide on scroll and drag
            $(document).on('scroll', function() {
                if (_$metaTip) _$metaTip.hide();
            });
        })();

        // Make tree nodes droppable for items
        // Track which node is hovered during external drag via mousemove
        // (jQuery UI droppable over/out is unreliable with nested nodes)

        $(document).on('mousemove', function(e) {
            if (!_dragActive) return;
            // Find the deepest jstree-anchor under the cursor
            const el = document.elementFromPoint(e.clientX, e.clientY);
            if (!el) {
                if (_lastHoverId) {
                    $('#kookoawpf-jstree .kookoawpf-drop-hover').removeClass('kookoawpf-drop-hover');
                    _lastHoverId = null;
                }
                return;
            }
            const $anchor = $(el).closest('.jstree-anchor');
            const $node = $anchor.length ? $anchor.closest('.jstree-node') : null;
            const nodeId = $node ? $node.attr('id') : null;

            if (nodeId === _lastHoverId) return;
            _lastHoverId = nodeId;

            $('#kookoawpf-jstree .kookoawpf-drop-hover').removeClass('kookoawpf-drop-hover');
            if ($node) {
                // Don't show drop indicator on dynamic/smart folders
                const inst = self.tree.jstree(true);
                const treeNode = inst ? inst.get_node(nodeId) : null;
                if (treeNode && treeNode.data && treeNode.data.is_dynamic) return;
                $node.addClass('kookoawpf-drop-hover');
            }
        });

        const dropOpts = {
            accept: '.wp-list-table tbody tr, .attachments-browser .attachment',
            tolerance: 'pointer', greedy: true,
            drop: function(event, ui) {
                $('#kookoawpf-jstree .kookoawpf-drop-hover').removeClass('kookoawpf-drop-hover');
                _dragActive = false;
                _lastHoverId = null;
                const treeNode = self.tree.jstree('get_node', $(this).attr('id'));
                if (!treeNode) return;

                // Reject drops on dynamic (smart) folders
                if (treeNode.data && treeNode.data.is_dynamic) {
                    self.showNotice(self.data.strings.smartAutoPopulated, 'warning');
                    return;
                }

                const targetId = self.getFolderId(treeNode);
                const isGrid = ui.draggable.hasClass('attachment');
                const postIds = self._getDragIds(ui.draggable, isGrid ? 'grid' : 'list');

                if (postIds.length && targetId) {
                    self.ajax('kookoawpf_move_items', {
                        post_ids: postIds,
                        from_folder_id: self.getFromFolderId(),
                        to_folder_id: targetId,
                        post_type: self.data.postType
                    }, function(r) {
                        if (r.success) {
                            self.refreshTree(function() {
                                self._countsAreFresh = true;
                                self._refreshContentView();
                            });
                            self.showNotice(
                                postIds.length > 1
                                    ? postIds.length + ' ' + self.data.strings.itemsMoved
                                    : self.data.strings.moveTo,
                                'success'
                            );
                        }
                    });
                }
            }
        };
        self._dropOpts = dropOpts;
        function makeNodeDroppable($node) {
            if ($node.data('fo-dp')) return;
            $node.data('fo-dp', true);
            $node.droppable(dropOpts);
        }
        self._makeNodeDroppable = makeNodeDroppable;
        $(document).on('mouseenter', '#kookoawpf-jstree .jstree-node', function() {
            const $node = $(this);
            makeNodeDroppable($node);
            $node.children('.jstree-children').find('.jstree-node').each(function() {
                makeNodeDroppable($(this));
            });
        });

        // Uncategorized droppable
        $('.kookoawpf-nav-uncategorized').droppable({
            accept: '.wp-list-table tbody tr, .attachments-browser .attachment',
            hoverClass: 'kookoawpf-drop-hover', tolerance: 'pointer',
            drop: function(e, ui) {
                const isGrid = ui.draggable.hasClass('attachment');
                const postIds = self._getDragIds(ui.draggable, isGrid ? 'grid' : 'list');
                if (!postIds.length || self.currentFolder === 'uncategorized') return;
                // From a specific folder → unassign from that folder only.
                // From "all" → folder_id=0 sentinel, server strips every
                // folder term (the item becomes uncategorized regardless of
                // which folders previously claimed it).
                const folderId = (self.currentFolder === 'all') ? 0 : self.currentFolder;
                self.ajax('kookoawpf_unassign_items', {
                    post_ids: postIds,
                    folder_id: folderId,
                    post_type: self.data.postType
                }, function(r) {
                    if (r.success) {
                        self.refreshTree(function() {
                            self._countsAreFresh = true;
                            self._refreshContentView();
                        });
                    }
                });
            }
        });
    };

    /**
     * Initialize draggable on a single list table row.
     */
    FO._initRowDraggable = function($row) {
        const self = this;
        if ($row.data('fo-d')) return;
        $row.data('fo-d', true);

        $row.draggable({
            helper: function() {
                return FO._createDragHelper($(this));
            },
            appendTo: 'body', cursor: 'move',
            cursorAt: { left: 10, top: 10 }, distance: 10,
            revert: 'invalid', zIndex: 999999,
            start: function() {
                if (FO.isCurrentFolderSmart && FO.isCurrentFolderSmart()) return false;
                if (self._dragState) { self._dragState.setActive(true); }
                $('body').addClass('kookoawpf-dragging');
            },
            stop: function() { if (self._dragState) { self._dragState.setActive(false); self._dragState.resetHover(); } $('body').removeClass('kookoawpf-dragging'); $('#kookoawpf-jstree .kookoawpf-drop-hover').removeClass('kookoawpf-drop-hover'); }
        });
    };

    /**
     * Initialize draggable on all current list table rows.
     * Called after _loadList replaces tbody content.
     */
    FO._makeListRowsDraggable = function() {
        const self = this;
        $('.wp-list-table tbody tr').each(function() {
            self._initRowDraggable($(this));
        });
    };

    /**
     * Re-initialize droppable on all tree nodes.
     * Called after refreshTree rebuilds the jsTree DOM.
     */
    FO._makeTreeNodesDroppable = function() {
        const self = this;
        if (!self._makeNodeDroppable) return;
        $('#kookoawpf-jstree .jstree-node').each(function() {
            self._makeNodeDroppable($(this));
        });
    };

})(jQuery);
