/**
 * Shared DataTables + datepicker init for Koha report screens.
 */
(function ($) {
  'use strict';

  function showTableLoading($scope) {
    var $el = ($scope && $scope.length)
      ? $scope.find('.krc-report-loading').first()
      : $('#krcTableLoading, .report-table-stage .krc-report-loading').first();
    if (!$el.length) {
      $el = $('.krc-report-loading').first();
    }
    if (!$el.length) {
      return;
    }
    $el.removeClass('is-hidden').attr('aria-busy', 'true');
  }

  function hideTableLoading($scope) {
    var $el = ($scope && $scope.length)
      ? $scope.find('.krc-report-loading')
      : $('.krc-report-loading');
    $el.addClass('is-hidden').attr('aria-busy', 'false');
  }

  function baseTableOptions(pageLength) {
    return {
      paging: true,
      searching: true,
      info: true,
      lengthChange: true,
      ordering: true,
      pageLength: pageLength || 25,
      lengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, 'All']],
      order: [],
      // Keep header + body in one table so columns stay aligned
      autoWidth: true,
      // Use Bootstrap 4 default dom from dataTables.bootstrap4.js
      language: {
        search: 'Search:',
        lengthMenu: 'Show _MENU_ rows',
        info: 'Showing _START_ to _END_ of _TOTAL_ records',
        infoEmpty: 'Showing 0 to 0 of 0 records',
        infoFiltered: '(filtered from _MAX_ total records)',
        zeroRecords: 'No matching records',
        emptyTable: 'No data loaded. Use Search to load results.',
        paginate: {
          first: 'First',
          last: 'Last',
          next: 'Next',
          previous: 'Previous'
        }
      }
    };
  }

  function preventFilterFormSubmit($table) {
    // Search box is inside <form method="post"> — stop Enter from submitting the report form
    var $wrap = $table.closest('.dataTables_wrapper');
    $wrap.find('.dataTables_filter input').on('keydown', function (e) {
      if (e.key === 'Enter' || e.which === 13) {
        e.preventDefault();
        e.stopPropagation();
        return false;
      }
    });
  }

  function initClientTables() {
    if (!$.fn.DataTable) {
      return;
    }

    $('.js-report-datatable').not('.js-server-side').each(function () {
      var $table = $(this);
      if ($.fn.DataTable.isDataTable($table)) {
        return;
      }

      var pageLength = parseInt($table.data('page-length'), 10) || 25;
      try {
        var dt = $table.DataTable(baseTableOptions(pageLength));
        preventFilterFormSubmit($table);
        // Recalc widths after layout settles
        setTimeout(function () {
          dt.columns.adjust();
        }, 50);
      } catch (err) {
        if (window.console && console.error) {
          console.error('DataTable init failed:', err);
        }
      }
    });
  }

  function initServerSideTables() {
    if (!$.fn.DataTable) {
      return;
    }

    $('.js-report-datatable.js-server-side').each(function () {
      var $table = $(this);
      if ($.fn.DataTable.isDataTable($table)) {
        return;
      }

      var ajaxUrl = $table.data('ajax-url');
      if (!ajaxUrl) {
        return;
      }

      var $stage = $table.closest('.report-table-stage');
      var pageLength = parseInt($table.data('page-length'), 10) || 25;
      var columns = [];
      $table.find('thead th').each(function () {
        var key = $(this).attr('data-data') || $(this).data('data');
        columns.push({ data: key });
      });

      var opts = $.extend(true, {}, baseTableOptions(pageLength), {
        processing: true,
        serverSide: true,
        lengthMenu: $table.hasClass('js-lac-server-side')
          ? [[100, 200, 500], [100, 200, 500]]
          : [[10, 25, 50, 100], [10, 25, 50, 100]],
        columns: columns,
        ajax: {
          url: ajaxUrl,
          type: 'POST',
          data: function (d) {
            var $form = $table.closest('form');
            if ($table.hasClass('js-lac-server-side')) {
              // Prefer form values; fall back to server-rendered data-* (ISO) so AJAX
              // still works if datepicker/inputs are empty or JS cache is stale.
              var fromDate = '';
              var toDate = '';
              var fromYmd = $table.attr('data-lac-from-ymd') || '';
              var toYmd = $table.attr('data-lac-to-ymd') || '';
              if ($form.length) {
                fromDate = $.trim($form.find('[name="lac_from_date"]').val() || '');
                toDate = $.trim($form.find('[name="lac_to_date"]').val() || '');
                d.lac_member_count = $form.find('[name="lac_member_count"]').val();
                d.lac_member = $form.find('[name="lac_member[]"]').map(function () {
                  return $(this).val();
                }).get();
              }
              if (!fromDate) {
                fromDate = $table.attr('data-lac-from-date') || '';
              }
              if (!toDate) {
                toDate = $table.attr('data-lac-to-date') || '';
              }
              d.lac_from_date = fromDate;
              d.lac_to_date = toDate;
              d.lac_from_ymd = fromYmd;
              d.lac_to_ymd = toYmd;
            } else {
              var status = $('select[name="status[]"]').val();
              d.status = status && status.length ? status : ['ALL'];
            }
          },
          beforeSend: function () {
            showTableLoading($stage);
          },
          complete: function () {
            hideTableLoading($stage);
          },
          dataSrc: function (json) {
            var total = json.recordsFiltered != null ? json.recordsFiltered : json.recordsTotal;
            if ($table.hasClass('js-lac-server-side')) {
              $('.js-lac-total').text(total != null ? total : '0');
            } else {
              $('.js-accession-total').text(total != null ? total : '0');
            }
            var $bar = $table.closest('form').find('.report-export-bar').first();
            if ($bar.length && total != null) {
              $bar.attr('data-export-rows', total).data('export-rows', total);
            }
            return json.data || [];
          }
        },
        language: $.extend({}, baseTableOptions().language, {
          emptyTable: $table.hasClass('js-lac-server-side')
            ? 'No matching LAC titles.'
            : 'No matching accession records.',
          processing: 'Loading…'
        })
      });

      try {
        var dt = $table.DataTable(opts);
        preventFilterFormSubmit($table);
        setTimeout(function () {
          dt.columns.adjust();
        }, 50);
      } catch (err) {
        if (window.console && console.error) {
          console.error('Server DataTable init failed:', err);
        }
      }
    });
  }

  function wrapDateInput($input) {
    if ($input.parent().hasClass('js-date-wrap')) {
      return $input.parent();
    }
    var $group = $('<div class="input-group js-date-wrap"></div>');
    $input.after($group);
    $group.append($input.detach());
    var $btn = $(
      '<div class="input-group-append">' +
        '<div class="input-group-text" role="button" tabindex="0" title="Pick date">' +
          '<i class="fas fa-calendar-alt"></i>' +
        '</div>' +
      '</div>'
    );
    $group.append($btn);
    $btn.on('click keypress', function (e) {
      if (e.type === 'keypress' && e.which !== 13 && e.which !== 32) {
        return;
      }
      e.preventDefault();
      $input.datepicker('show');
    });
    return $group;
  }

  function initDatePickers() {
    if (!$.fn.datepicker || !$.datepicker || typeof $.datepicker.setDefaults !== 'function') {
      return;
    }

    $('.js-date').each(function () {
      var $input = $(this);
      if ($input.data('krc-dp-ready')) {
        return;
      }

      $input
        .removeClass('datetimepicker-input')
        .removeAttr('data-toggle')
        .removeAttr('data-target')
        .attr('autocomplete', 'off')
        .attr('placeholder', $input.attr('placeholder') || 'dd-mm-yyyy');

      wrapDateInput($input);

      $input.datepicker({
        dateFormat: 'dd-mm-yy',
        changeMonth: true,
        changeYear: true,
        yearRange: 'c-25:c+5',
        showAnim: 'fadeIn',
        showButtonPanel: false,
        beforeShow: function (input, inst) {
          setTimeout(function () {
            inst.dpDiv.css({ zIndex: 10050 });
          }, 0);
        }
      });

      $input.data('krc-dp-ready', true);
    });
  }

  function initSelect2() {
    if (!$.fn.select2) {
      return;
    }
    $('.js-select2').each(function () {
      var $el = $(this);
      if ($el.hasClass('select2-hidden-accessible')) {
        return;
      }
      var opts = { theme: 'bootstrap4', width: '100%' };
      if ($el.prop('multiple')) {
        opts.closeOnSelect = false;
        opts.placeholder = $el.data('placeholder') || 'Select…';
        opts.allowClear = true;
      }
      $el.select2(opts);

      if ($el.prop('multiple') && ($el.find('option[value="ALL"]').length || $el.find('option[value="All"]').length)) {
        $el.on('select2:select', function (e) {
          var val = e.params && e.params.data ? e.params.data.id : null;
          var selected = $el.val() || [];
          if (val === 'ALL' || val === 'All') {
            $el.val([val]).trigger('change');
          } else if (selected.indexOf('ALL') !== -1 || selected.indexOf('All') !== -1) {
            selected = selected.filter(function (v) { return v !== 'ALL' && v !== 'All'; });
            $el.val(selected).trigger('change');
          }
        });
      }
    });
  }

  function ensurePageLoadingOverlay() {
    if ($('#krcPageLoading').length) {
      return;
    }
    $('body').append(
      '<div id="krcPageLoading" class="krc-page-loading is-hidden" aria-live="polite" aria-busy="false">' +
        '<div class="krc-report-loading-inner krc-export-panel">' +
          '<i class="fas fa-sync-alt fa-spin krc-export-icon"></i>' +
          '<span class="krc-export-msg">Loading report data&hellip;</span>' +
          '<div class="krc-export-progress is-hidden">' +
            '<div class="krc-export-bar"><div class="krc-export-bar-fill" style="width:0%"></div></div>' +
            '<div class="krc-export-meta">' +
              '<span class="krc-export-pct">0%</span>' +
              '<span class="krc-export-eta">Estimating time&hellip;</span>' +
            '</div>' +
            '<div class="krc-export-detail"></div>' +
            '<div class="krc-export-finish"></div>' +
          '</div>' +
        '</div>' +
      '</div>'
    );
  }

  function showPageLoading() {
    ensurePageLoadingOverlay();
    $('#krcPageLoading').removeClass('is-hidden').attr('aria-busy', 'true');
  }

  function hidePageLoading() {
    $('#krcPageLoading').addClass('is-hidden').attr('aria-busy', 'false');
    stopExportProgressPoll();
  }

  function getCookie(name) {
    var match = document.cookie.match(new RegExp('(?:^|; )' + name.replace(/([.$?*|{}()[\]\\/+^])/g, '\\$1') + '=([^;]*)'));
    return match ? decodeURIComponent(match[1]) : '';
  }

  function clearDownloadCookie() {
    document.cookie = 'kohaDownloadToken=; Path=/; Max-Age=0';
  }

  var exportProgressTimer = null;
  var exportProgressXhr = null;

  function stopExportProgressPoll() {
    if (exportProgressTimer) {
      window.clearInterval(exportProgressTimer);
      exportProgressTimer = null;
    }
    if (exportProgressXhr && exportProgressXhr.abort) {
      try { exportProgressXhr.abort(); } catch (e) {}
      exportProgressXhr = null;
    }
  }

  function formatDuration(seconds) {
    seconds = Math.max(0, Math.floor(seconds || 0));
    if (seconds < 60) {
      return seconds + 's';
    }
    var m = Math.floor(seconds / 60);
    var s = seconds % 60;
    if (m < 60) {
      return m + 'm ' + s + 's';
    }
    var h = Math.floor(m / 60);
    m = m % 60;
    return h + 'h ' + m + 'm';
  }

  function formatClock(ts) {
    if (!ts) {
      return '';
    }
    var d = new Date(ts * 1000);
    if (isNaN(d.getTime())) {
      return '';
    }
    return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
  }

  function setExportOverlayMode(isPdf, rowCount) {
    ensurePageLoadingOverlay();
    var $overlay = $('#krcPageLoading');
    var $progress = $overlay.find('.krc-export-progress');
    var $icon = $overlay.find('.krc-export-icon');
    if (isPdf) {
      $icon.removeClass('fa-sync-alt').addClass('fa-file-pdf');
      $progress.removeClass('is-hidden');
      $overlay.find('.krc-export-msg').text(
        rowCount > 0
          ? ('Preparing PDF for ' + rowCount.toLocaleString() + ' rows…')
          : 'Preparing PDF…'
      );
      $overlay.find('.krc-export-bar-fill').css('width', '1%');
      $overlay.find('.krc-export-pct').text('0%');
      $overlay.find('.krc-export-eta').text('Estimating time…');
      $overlay.find('.krc-export-detail').text('');
      $overlay.find('.krc-export-finish').text('');
    } else {
      $icon.removeClass('fa-file-pdf').addClass('fa-sync-alt');
      $progress.addClass('is-hidden');
    }
  }

  function applyExportProgress(data) {
    if (!data || typeof data !== 'object') {
      return;
    }
    ensurePageLoadingOverlay();
    var $overlay = $('#krcPageLoading');
    var pct = Math.max(0, Math.min(100, parseInt(data.percent, 10) || 0));
    if (data.message) {
      $overlay.find('.krc-export-msg').text(data.message);
    }
    $overlay.find('.krc-export-bar-fill').css('width', pct + '%');
    $overlay.find('.krc-export-pct').text(pct + '%');

    var etaText = 'Estimating time…';
    if (data.status === 'done') {
      etaText = 'Complete';
    } else if (data.eta_seconds != null && data.eta_seconds !== '') {
      etaText = 'About ' + formatDuration(data.eta_seconds) + ' left';
    }
    $overlay.find('.krc-export-eta').text(etaText);

    var detail = '';
    if (data.current && data.total) {
      var unit = (data.message && String(data.message).indexOf('row') !== -1) ? 'Row' : 'Part';
      detail = unit + ' ' + Number(data.current).toLocaleString() + ' of ' + Number(data.total).toLocaleString();
      if (data.rows_done != null && data.rows_total && unit === 'Part') {
        detail += ' · ' + Number(data.rows_done).toLocaleString() + ' / ' + Number(data.rows_total).toLocaleString() + ' rows';
      }
    } else if (data.rows_total) {
      detail = Number(data.rows_total).toLocaleString() + ' rows';
    }
    $overlay.find('.krc-export-detail').text(detail);

    var finish = '';
    if (data.status !== 'done' && data.finish_at) {
      finish = 'Expected around ' + formatClock(data.finish_at);
    } else if (data.status === 'done') {
      finish = 'Download starting…';
    }
    $overlay.find('.krc-export-finish').text(finish);
  }

  function startExportProgressPoll(token, progressUrl, rowCount, chunkSize) {
    stopExportProgressPoll();
    if (!token || !progressUrl) {
      return;
    }

    // Client-side seed estimate until first server update
    var chunks = rowCount > 0 ? Math.max(1, Math.ceil(rowCount / (chunkSize || 35))) : 0;
    if (chunks > 0) {
      var seedEta = Math.ceil(chunks * 0.7 + Math.max(2, chunks * 0.02));
      applyExportProgress({
        status: 'starting',
        percent: 1,
        current: 0,
        total: chunks,
        rows_total: rowCount,
        rows_done: 0,
        eta_seconds: seedEta,
        finish_at: Math.floor(Date.now() / 1000) + seedEta,
        message: 'Preparing PDF for ' + rowCount.toLocaleString() + ' rows…'
      });
    }

    function pollOnce() {
      exportProgressXhr = $.ajax({
        url: progressUrl,
        data: { token: token },
        dataType: 'json',
        cache: false,
        timeout: 8000
      }).done(function (data) {
        if (data && data.status && data.status !== 'waiting' && data.status !== 'missing') {
          applyExportProgress(data);
        }
        if (data && (data.status === 'done' || data.status === 'error')) {
          stopExportProgressPoll();
        }
      });
    }

    pollOnce();
    exportProgressTimer = window.setInterval(pollOnce, 900);
  }

  function bindFormLoading() {
    $('.report-card form').each(function () {
      var $form = $(this);
      $form.find('button[type="submit"]').on('click', function () {
        var val = $(this).attr('value') || $(this).val() || 'search';
        $form.data('submit-action', val);
      });

      $form.on('submit', function () {
        var action = $form.data('submit-action') || 'search';
        var isExport = action === 'pdf' || action === 'excel' || action === 'word';
        var isPdf = action === 'pdf';
        var $bar = $form.find('.report-export-bar').first();
        var rowCount = parseInt($bar.data('export-rows'), 10) || 0;
        if (!rowCount) {
          var totalText = $form.find('.js-accession-total, .js-lac-total').first().text() || '';
          rowCount = parseInt(String(totalText).replace(/[^\d]/g, ''), 10) || 0;
        }
        var chunkSize = parseInt($bar.data('pdf-chunk-size'), 10) || 35;
        var progressUrl = $bar.data('progress-url') || '';

        ensurePageLoadingOverlay();
        setExportOverlayMode(isPdf, rowCount);

        if (!isExport) {
          $('#krcPageLoading').find('.krc-export-msg').html('Loading report data&hellip;');
        } else if (!isPdf) {
          $('#krcPageLoading').find('.krc-export-msg').html(
            'Preparing export — please wait, large reports can take a few minutes&hellip;'
          );
        }

        showPageLoading();

        window.clearTimeout($form.data('busyTimer'));
        window.clearInterval($form.data('busyPoll'));
        stopExportProgressPoll();

        if (!isExport) {
          return;
        }

        // Token cookie is set by server when file download starts → hide overlay
        var token = 'dl_' + Date.now() + '_' + Math.floor(Math.random() * 1e6);
        $form.find('input[name="download_token"]').remove();
        $form.append('<input type="hidden" name="download_token" value="' + token + '">');
        clearDownloadCookie();

        if (isPdf) {
          startExportProgressPoll(token, progressUrl, rowCount, chunkSize);
        }

        var poll = window.setInterval(function () {
          if (getCookie('kohaDownloadToken') === token) {
            window.clearInterval(poll);
            window.clearTimeout($form.data('busyTimer'));
            stopExportProgressPoll();
            clearDownloadCookie();
            applyExportProgress({
              status: 'done',
              percent: 100,
              message: 'PDF ready — download starting…',
              eta_seconds: 0
            });
            window.setTimeout(hidePageLoading, 400);
          }
        }, 400);
        $form.data('busyPoll', poll);

        // Safety: large PDFs (30k+) can take a long time — keep overlay up to 2 hours
        var configuredMs = parseInt($form.data('busy-export-ms'), 10);
        var ms;
        if (isPdf && rowCount > 0) {
          var estChunks = Math.ceil(rowCount / chunkSize);
          ms = Math.max(180000, Math.min(7200000, estChunks * 2500 + 120000));
          if (!isNaN(configuredMs) && configuredMs > ms) {
            ms = configuredMs;
          }
        } else {
          ms = (!isNaN(configuredMs) && configuredMs > 0) ? configuredMs : 180000;
        }
        $form.data('busyTimer', window.setTimeout(function () {
          window.clearInterval(poll);
          stopExportProgressPoll();
          hidePageLoading();
        }, ms));
      });
    });
  }

  function bindLacMemberFields() {
    $('.js-lac-members-form').each(function () {
      var $form = $(this);
      var $count = $form.find('.js-lac-member-count');
      var $wrap = $form.find('.js-lac-member-fields');
      var $hint = $form.find('.js-lac-member-hint');
      if (!$count.length || !$wrap.length) {
        return;
      }

      var inputName = $form.attr('data-member-input-name') || 'lac_member[]';
      var maxLen = parseInt($form.attr('data-member-maxlen'), 10);
      if (!maxLen || maxLen < 1) {
        maxLen = inputName.indexOf('weed_') === 0 ? 40 : 12;
      }

      function renderEmptyFields(count, focusFirst) {
        count = parseInt(count, 10);
        if (!count || count < 1) {
          $wrap.empty();
          $hint.removeClass('d-none');
          return;
        }
        count = Math.min(20, count);
        var html = '';
        for (var i = 0; i < count; i++) {
          html +=
            '<div class="col-6 col-sm-4 col-md-3 col-lg-2 mb-2 js-lac-member-field">' +
              '<input type="text" class="form-control form-control-sm text-uppercase js-lac-member-input" ' +
                'name="' + inputName + '" maxlength="' + maxLen + '" required value="" ' +
                'placeholder="Member ' + (i + 1) + '" ' +
                'title="Member ' + (i + 1) + '">' +
            '</div>';
        }
        $wrap.html(html);
        $hint.addClass('d-none');
        if (focusFirst) {
          setTimeout(function () {
            var $first = $wrap.find('.js-lac-member-input').first();
            if ($first.length) {
              $first.trigger('focus');
            }
          }, 0);
        }
      }

      function syncFields(focusFirst) {
        var count = parseInt($count.val(), 10) || 0;
        var current = $wrap.find('.js-lac-member-field').length;
        if (count === current) {
          return;
        }
        renderEmptyFields(count, !!focusFirst);
      }

      $count.on('input', function () {
        syncFields(true);
      });

      $count.on('change', function () {
        syncFields(false);
      });

      var startCount = parseInt($count.val(), 10);
      if (startCount > 0 && !$wrap.find('.js-lac-member-field').length) {
        renderEmptyFields(startCount, false);
      }
    });
  }

  $(function () {
    hidePageLoading();
    hideTableLoading();

    // DataTables first so a Select2/datepicker error cannot block controls
    initClientTables();
    initServerSideTables();
    initDatePickers();
    initSelect2();
    bindFormLoading();
    bindLacMemberFields();
  });

  $(window).on('pageshow', function () {
    hidePageLoading();
    hideTableLoading();
  });

  $(window).on('resize', function () {
    if (!$.fn.DataTable) {
      return;
    }
    $('.js-report-datatable').each(function () {
      var $table = $(this);
      if ($.fn.DataTable.isDataTable($table)) {
        $table.DataTable().columns.adjust();
      }
    });
  });
})(jQuery);
