(function($) {
  'use strict';
  var D = window.ElsDash;
  var CONFIG = D.CONFIG;
  var COLS = D.COLS;

  function col(row, key) {
    var v = row[COLS[key]];
    return (v == null) ? '' : String(v).trim();
  }

  function normalizeStatus(raw) {
    var s = raw.toLowerCase();
    if (s === 'pending') return CONFIG.STATUS.PENDING;
    if (s === 'submitted') return CONFIG.STATUS.SUBMITTED;
    if (s === 'assigned') return CONFIG.STATUS.ASSIGNED;
    if (s === 'processing' || s === 'referred') return CONFIG.STATUS.REFERRED;
    if (s === 'granted') return CONFIG.STATUS.GRANTED;
    if (s === 'denied' || s === 'dismissed' || s === 'denied/dismissed') return CONFIG.STATUS.DENIED;
    if (s === 'expired') return CONFIG.STATUS.EXPIRED;
    return raw;
  }

  function parseDate(str) {
    if (!str) return null;
    var d = new Date(str);
    return isNaN(d.getTime()) ? null : d;
  }

  function daysBetween(d1, d2) {
    return Math.round((d2 - d1) / (1000 * 60 * 60 * 24));
  }

  function median(arr) {
    if (!arr.length) return 0;
    var sorted = arr.slice().sort(function(a, b) { return a - b; });
    var mid = Math.floor(sorted.length / 2);
    return sorted.length % 2 ? sorted[mid] : Math.round((sorted[mid - 1] + sorted[mid]) / 2);
  }

  function dmsToDecimal(deg, min, sec, dir) {
    deg = parseFloat(deg) || 0;
    min = parseFloat(min) || 0;
    sec = parseFloat(sec) || 0;
    var decimal = deg + min / 60 + sec / 3600;
    if (dir === 'S' || dir === 'W') decimal *= -1;
    return decimal;
  }

  function radiusToMeters(val) {
    var r = parseFloat(val) || 0;
    return CONFIG.RADIUS_UNIT_KM ? r * 1000 : r * 1609.34;
  }

  function formatDate(d) {
    if (!d) return '—';
    var mm = ('0' + (d.getMonth() + 1)).slice(-2);
    var dd = ('0' + d.getDate()).slice(-2);
    return mm + '/' + dd + '/' + d.getFullYear();
  }

  function getReportPeriod() {
    return ($('#period-selector').val() || 'monthly');
  }

  function periodKey(d, period) {
    var y = d.getFullYear();
    var m = d.getMonth();
    if (period === 'weekly') {
      var jan1 = new Date(y, 0, 1);
      var days = Math.floor((d - jan1) / 86400000);
      var week = Math.ceil((days + jan1.getDay() + 1) / 7);
      return y + '-W' + ('0' + week).slice(-2);
    }
    if (period === 'quarterly') {
      var q = Math.floor(m / 3) + 1;
      return y + '-Q' + q;
    }
    return y + '-' + ('0' + (m + 1)).slice(-2);
  }

  function periodLabel(key) {
    if (key.indexOf('-W') !== -1) return key;
    if (key.indexOf('-Q') !== -1) return key;
    var parts = key.split('-');
    return parts[1] + '/' + parts[0].slice(2);
  }

  function periodOffset(period) {
    if (period === 'weekly') return 13;
    if (period === 'quarterly') return 1;
    return 3;
  }

  function isPending(status) {
    return status === CONFIG.STATUS.PENDING || status === CONFIG.STATUS.SUBMITTED || status === CONFIG.STATUS.ASSIGNED || status === CONFIG.STATUS.REFERRED;
  }

  function statusColor(status) {
    switch (status) {
      case CONFIG.STATUS.PENDING:    return CONFIG.COLORS.PRIMARY;
      case CONFIG.STATUS.SUBMITTED:  return '#4a90d9';
      case CONFIG.STATUS.ASSIGNED:   return '#2f69b2';
      case CONFIG.STATUS.REFERRED:   return CONFIG.COLORS.PRIMARY;
      case CONFIG.STATUS.GRANTED:    return CONFIG.COLORS.SUCCESS;
      case CONFIG.STATUS.DENIED:     return CONFIG.COLORS.DANGER;
      case CONFIG.STATUS.EXPIRED:    return CONFIG.COLORS.NEUTRAL;
      default: return CONFIG.COLORS.NEUTRAL;
    }
  }

  function statusBadgeClass(status) {
    switch (status) {
      case CONFIG.STATUS.PENDING:    return 'badge-pending';
      case CONFIG.STATUS.SUBMITTED:  return 'badge-submitted';
      case CONFIG.STATUS.ASSIGNED:   return 'badge-assigned';
      case CONFIG.STATUS.REFERRED:   return 'badge-referred';
      case CONFIG.STATUS.GRANTED:    return 'badge-granted';
      case CONFIG.STATUS.DENIED:     return 'badge-denied';
      case CONFIG.STATUS.EXPIRED:    return 'badge-expired';
      default: return 'badge-pending';
    }
  }

  function debounce(fn, delay) {
    var timer;
    return function() {
      clearTimeout(timer);
      timer = setTimeout(fn, delay);
    };
  }

  function formatFreq(lo, hi) {
    if (!lo) return '—';
    return hi ? lo + ' – ' + hi + ' MHz' : lo + ' MHz';
  }

  function appKey(app) {
    return app.fileNumber + '|' + app.callsign;
  }

  function appLabel(app) {
    return app.fileNumber + (app.callsign ? ' / ' + app.callsign : '');
  }

  D.helpers = {
    col: col,
    normalizeStatus: normalizeStatus,
    parseDate: parseDate,
    daysBetween: daysBetween,
    median: median,
    dmsToDecimal: dmsToDecimal,
    radiusToMeters: radiusToMeters,
    formatDate: formatDate,
    getReportPeriod: getReportPeriod,
    periodKey: periodKey,
    periodLabel: periodLabel,
    periodOffset: periodOffset,
    isPending: isPending,
    statusColor: statusColor,
    statusBadgeClass: statusBadgeClass,
    debounce: debounce,
    formatFreq: formatFreq,
    appKey: appKey,
    appLabel: appLabel
  };
})(jQuery);
