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

  D.fridayCharts = {};

  // ============================================================
  // FRIDAY REPORT TAB
  // ============================================================
  function updateFridayReport() {
    var now = new Date();
    now.setHours(0, 0, 0, 0);
    var dow = now.getDay(); // 0=Sun 1=Mon ... 5=Fri 6=Sat

    // Weeks run Sat-Fri (no gaps). Find the current partial week,
    // the most recent completed week, and the week before that.
    var daysBackToSat = (dow + 1) % 7;
    var curWeekSat = new Date(now.getFullYear(), now.getMonth(), now.getDate() - daysBackToSat);
    var lastFri = new Date(curWeekSat.getFullYear(), curWeekSat.getMonth(), curWeekSat.getDate() - 1);
    var lastSat = new Date(lastFri.getFullYear(), lastFri.getMonth(), lastFri.getDate() - 6);
    var prevFri = new Date(lastSat.getFullYear(), lastSat.getMonth(), lastSat.getDate() - 1);
    var prevSat = new Date(prevFri.getFullYear(), prevFri.getMonth(), prevFri.getDate() - 6);

    // inRange: date >= weekStart and < dayAfterEnd
    function inRange(d, wkStart, fri) {
      if (!d) return false;
      var dayAfter = new Date(fri.getFullYear(), fri.getMonth(), fri.getDate() + 1);
      return d >= wkStart && d < dayAfter;
    }
    function inCurrentRange(d) {
      if (!d) return false;
      var tomorrow = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
      return d >= curWeekSat && d < tomorrow;
    }

    // Header
    var curDayName = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][dow];
    var headerText = '-- ' + H.formatDate(lastSat) + ' - ' + H.formatDate(lastFri);
    headerText += '  (current week through ' + curDayName + ')';
    $('#fr-date-range').text(headerText);

    // Collect metrics for last week, week before, and current week
    function countInRange(mon, fri) {
      var newApps = D.allApps.filter(function(a) { return inRange(a.receiptDate, mon, fri); });
      var completed = D.allApps.filter(function(a) { return !H.isPending(a.status) && inRange(a.statusDate, mon, fri); });
      var refOpened = 0, refClosed = 0;
      D.allApps.forEach(function(a) {
        a.charges.forEach(function(c) {
          if (inRange(c.openDate, mon, fri)) refOpened++;
          if (inRange(c.closeDate, mon, fri)) refClosed++;
        });
      });
      return { newApps: newApps.length, completed: completed.length, refOpened: refOpened, refClosed: refClosed };
    }

    var lastWeek = countInRange(lastSat, lastFri);
    var weekBefore = countInRange(prevSat, prevFri);

    var curWeek = null;
    {
      var curNewApps = D.allApps.filter(function(a) { return inCurrentRange(a.receiptDate); });
      var curCompleted = D.allApps.filter(function(a) { return !H.isPending(a.status) && inCurrentRange(a.statusDate); });
      var curRefOpened = 0, curRefClosed = 0;
      D.allApps.forEach(function(a) {
        a.charges.forEach(function(c) {
          if (inCurrentRange(c.openDate)) curRefOpened++;
          if (inCurrentRange(c.closeDate)) curRefClosed++;
        });
      });
      curWeek = { newApps: curNewApps.length, completed: curCompleted.length, refOpened: curRefOpened, refClosed: curRefClosed };
    }

    function wowBadge(current, previous) {
      if (previous === 0 && current === 0) return '<span class="trend-flat">--</span>';
      if (previous === 0) return '<span class="trend-new"><i class="fa fa-star"></i> new</span>';
      var delta = current - previous;
      var pct = Math.round((delta / previous) * 100);
      if (delta > 0) return '<span class="trend-up"><i class="fa fa-arrow-up"></i> +' + delta + ' (+' + pct + '%)</span>';
      if (delta < 0) return '<span class="trend-down"><i class="fa fa-arrow-down"></i> ' + delta + ' (' + pct + '%)</span>';
      return '<span class="trend-flat"><i class="fa fa-minus"></i> 0</span>';
    }

    // upIsGood: false means increase = bad (red), decrease = good (green)
    function pctColor(current, previous, upIsGood) {
      if (previous === 0 || current === previous) return '#555';
      var up = current > previous;
      if (upIsGood) return up ? '#2e8540' : '#ff253a';
      return up ? '#ff253a' : '#2e8540';
    }

    function pctDisplay(current, previous) {
      if (previous === 0 && current === 0) return '--';
      if (previous === 0) return 'NEW';
      var delta = current - previous;
      var pct = Math.round((delta / previous) * 100);
      var sign = delta > 0 ? '+' : '';
      return sign + pct + '%';
    }

    // Current week in-progress banner
    var kpiHtml = '';
    if (curWeek) {
      kpiHtml += '<div style="background:#fffbe6;border:2px solid #ffbe2e;border-radius:4px;padding:12px 16px;margin-bottom:15px;display:flex;align-items:center;flex-wrap:wrap;gap:20px">' +
        '<div style="font-weight:700;color:#333"><i class="fa fa-clock-o"></i> This Week So Far <span style="font-weight:400;color:#888">(' + H.formatDate(curWeekSat) + ' - today)</span></div>' +
        '<div style="font-size:0.95rem">' +
          '<span style="margin-right:16px"><strong style="color:#13418A">' + curWeek.newApps + '</strong> new</span>' +
          '<span style="margin-right:16px"><strong style="color:#2e8540">' + curWeek.completed + '</strong> completed</span>' +
          '<span style="margin-right:16px"><strong style="color:#e86e00">' + curWeek.refOpened + '</strong> ref. opened</span>' +
          '<span><strong style="color:#2e8540">' + curWeek.refClosed + '</strong> ref. closed</span>' +
        '</div>' +
        '</div>';
    }

    // Pending counts for extra KPIs
    var pendingApps = D.allApps.filter(function(a) { return H.isPending(a.status); });
    var pendingAges = pendingApps.map(function(a) { return a.receiptDate ? H.daysBetween(a.receiptDate, now) : 0; }).sort(function(x, y) { return x - y; });
    var medianPending = H.median(pendingAges);
    var openRefs = 0;
    D.allApps.forEach(function(a) { a.charges.forEach(function(c) { if (c.openDate && !c.closeDate) openRefs++; }); });

    // KPIs: percentage change as main number, counts smaller
    // upIsGood: false for New Apps (more = more work), true for others (completing/closing = good)
    var kpis = [
      { label: 'New Applications', value: lastWeek.newApps, prev: weekBefore.newApps, upIsGood: false },
      { label: 'Completed', value: lastWeek.completed, prev: weekBefore.completed, upIsGood: true },
      { label: 'Referrals Opened', value: lastWeek.refOpened, prev: weekBefore.refOpened, upIsGood: false },
      { label: 'Referrals Closed', value: lastWeek.refClosed, prev: weekBefore.refClosed, upIsGood: true },
      { label: 'Total Pending', value: pendingApps.length, prev: null, upIsGood: false },
      { label: 'Open Referrals', value: openRefs, prev: null, upIsGood: false }
    ];
    kpis.forEach(function(k) {
      var hasPrev = k.prev !== null;
      var mainColor = hasPrev ? pctColor(k.value, k.prev, k.upIsGood) : '#13418A';
      var mainText = hasPrev ? pctDisplay(k.value, k.prev) : k.value;
      var subText = hasPrev
        ? '<div class="fr-kpi-sub">' + k.value + ' last week vs ' + k.prev + ' prior</div>'
        : (k.label === 'Total Pending'
          ? '<div class="fr-kpi-sub">Median age: ' + medianPending + ' days</div>'
          : '');
      kpiHtml += '<div class="fr-kpi">' +
        '<div class="fr-kpi-label">' + k.label + '</div>' +
        '<div class="fr-kpi-value" style="color:' + mainColor + '">' + mainText + '</div>' +
        subText +
        '</div>';
    });
    $('#fr-kpi-row').html(kpiHtml);

    // Pipeline breakdown (current state)
    var submitted = D.allApps.filter(function(a) { return a.status === CONFIG.STATUS.SUBMITTED; });
    var assigned = D.allApps.filter(function(a) { return a.status === CONFIG.STATUS.ASSIGNED; });
    var referred = D.allApps.filter(function(a) { return a.status === CONFIG.STATUS.REFERRED; });

    // Split referred into sub-categories
    var refSingle = [], refMultiOneOpen = [], refMultiOpen = [];
    referred.forEach(function(a) {
      var total = a.charges.length;
      var openCount = a.charges.filter(function(c) { return c.openDate && !c.closeDate; }).length;
      if (total <= 1) {
        refSingle.push(a);
      } else if (openCount <= 1) {
        refMultiOneOpen.push(a);
      } else {
        refMultiOpen.push(a);
      }
    });

    var totalPending = submitted.length + assigned.length + referred.length;

    var barHtml = '';
    if (totalPending > 0) {
      var segments = [
        { count: submitted.length, label: 'Submitted', bg: '#4a90d9' },
        { count: assigned.length, label: 'Assigned', bg: '#2f69b2' },
        { count: refSingle.length, label: '1 Ref', bg: '#1a5bb8' },
        { count: refMultiOneOpen.length, label: 'Multi (1 open)', bg: '#13418A' },
        { count: refMultiOpen.length, label: 'Multi open', bg: '#0d2d6b' }
      ];
      var usedPct = 0;
      segments.forEach(function(s, i) {
        if (s.count === 0) return;
        var pct = (i === segments.length - 1) ? Math.max(0, 100 - usedPct) : Math.round(s.count / totalPending * 100);
        usedPct += pct;
        barHtml += '<div class="fr-seg" style="width:' + pct + '%;background:' + s.bg + '">' + s.count + '</div>';
      });
    } else {
      barHtml = '<div class="fr-seg" style="width:100%;background:#aeb0b5">No pending applications</div>';
    }
    $('#fr-pipeline-bar').html(barHtml);

    var cardStyle = 'background:#f5f8ff;border:1px solid #ddd;border-radius:4px;padding:10px 12px;flex:1;min-width:120px';
    var detailHtml =
      '<div style="' + cardStyle + '">' +
        '<div style="font-weight:700;color:#4a90d9;font-size:1.0rem"><i class="fa fa-inbox"></i> ' + submitted.length + ' Submitted</div>' +
        '<div style="font-size:0.8rem;color:#555">Not yet assigned</div>' +
      '</div>' +
      '<div style="' + cardStyle + '">' +
        '<div style="font-weight:700;color:#2f69b2;font-size:1.0rem"><i class="fa fa-user"></i> ' + assigned.length + ' Assigned</div>' +
        '<div style="font-size:0.8rem;color:#555">Under staff review</div>' +
      '</div>' +
      '<div style="' + cardStyle + '">' +
        '<div style="font-weight:700;color:#1a5bb8;font-size:1.0rem"><i class="fa fa-ellipsis-h"></i> ' + refSingle.length + ' Single Referral</div>' +
        '<div style="font-size:0.8rem;color:#555">1 referral only</div>' +
      '</div>' +
      '<div style="' + cardStyle + '">' +
        '<div style="font-weight:700;color:#13418A;font-size:1.0rem"><i class="fa fa-comment-o"></i> ' + refMultiOneOpen.length + ' Multi (1 open)</div>' +
        '<div style="font-size:0.8rem;color:#555">Multiple refs, 1 outstanding</div>' +
      '</div>' +
      '<div style="' + cardStyle + '">' +
        '<div style="font-weight:700;color:#0d2d6b;font-size:1.0rem"><i class="fa fa-comments-o"></i> ' + refMultiOpen.length + ' Multi open</div>' +
        '<div style="font-size:0.8rem;color:#555">Multiple refs outstanding</div>' +
      '</div>';
    $('#fr-pipeline-detail').html(detailHtml);

    // Referral entity breakdown (last week activity, WoW vs week before)
    var entityData = {};
    D.allApps.forEach(function(a) {
      a.charges.forEach(function(c) {
        if (!c.charge) return;
        if (!entityData[c.charge]) entityData[c.charge] = { open: 0, newLast: 0, closedLast: 0, newPrev: 0, ages: [] };
        if (c.openDate && !c.closeDate) {
          entityData[c.charge].open++;
          entityData[c.charge].ages.push(H.daysBetween(c.openDate, now));
        }
        if (inRange(c.openDate, lastSat, lastFri)) entityData[c.charge].newLast++;
        if (inRange(c.openDate, prevSat, prevFri)) entityData[c.charge].newPrev++;
        if (inRange(c.closeDate, lastSat, lastFri)) entityData[c.charge].closedLast++;
      });
    });

    var $ebody = $('#fr-entity-body');
    $ebody.empty();
    var entityKeys = Object.keys(entityData).sort();
    entityKeys.forEach(function(entity) {
      var ed = entityData[entity];
      var avgAge = ed.ages.length ? Math.round(ed.ages.reduce(function(s, v) { return s + v; }, 0) / ed.ages.length) : 0;
      $ebody.append(
        '<tr>' +
          '<td style="font-weight:600;color:#13428b">' + entity + '</td>' +
          '<td><span style="font-weight:700;color:#ffbe2e">' + ed.open + '</span></td>' +
          '<td>' + ed.newLast + '</td>' +
          '<td>' + ed.closedLast + '</td>' +
          '<td>' + avgAge + '</td>' +
          '<td>' + wowBadge(ed.newLast, ed.newPrev) + '</td>' +
        '</tr>'
      );
    });
    if (!entityKeys.length) {
      $ebody.append('<tr><td colspan="6" style="text-align:center;color:#888;padding:20px">No referral data available.</td></tr>');
    }

    // Weekly trend chart (last 6 completed weeks + current if in progress)
    var weekLabels = [];
    var weekNew = [];
    var weekCompleted = [];
    var weekRefOpened = [];
    var weekRefClosed = [];
    for (var w = 5; w >= 0; w--) {
      var wSat = new Date(lastSat.getFullYear(), lastSat.getMonth(), lastSat.getDate() - w * 7);
      var wFri = new Date(wSat.getFullYear(), wSat.getMonth(), wSat.getDate() + 6);
      var wData = countInRange(wSat, wFri);
      weekLabels.push(H.formatDate(wSat));
      weekNew.push(wData.newApps);
      weekCompleted.push(wData.completed);
      weekRefOpened.push(wData.refOpened);
      weekRefClosed.push(wData.refClosed);
    }
    if (curWeek) {
      weekLabels.push(H.formatDate(curWeekSat) + '*');
      weekNew.push(curWeek.newApps);
      weekCompleted.push(curWeek.completed);
      weekRefOpened.push(curWeek.refOpened);
      weekRefClosed.push(curWeek.refClosed);
    }

    if (D.fridayCharts.trend) D.fridayCharts.trend.destroy();
    D.fridayCharts.trend = new Chart(document.getElementById('chart-friday-trend'), {
      type: 'bar',
      data: {
        labels: weekLabels,
        datasets: [
          { label: 'New Apps', data: weekNew, backgroundColor: '#13418A99', borderColor: '#13418A', borderWidth: 1 },
          { label: 'Completed', data: weekCompleted, backgroundColor: '#2e854099', borderColor: '#2e8540', borderWidth: 1 },
          { label: 'Referrals Opened', data: weekRefOpened, type: 'line', borderColor: '#e86e00', backgroundColor: '#e86e0033', borderWidth: 2, fill: false, tension: 0.3, pointRadius: 4 },
          { label: 'Referrals Closed', data: weekRefClosed, type: 'line', borderColor: '#2e8540', backgroundColor: '#2e854033', borderWidth: 2, fill: false, tension: 0.3, pointRadius: 4, borderDash: [5, 5] }
        ]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: { legend: { position: 'bottom' } },
        scales: { y: { beginAtZero: true, ticks: { stepSize: 1 } } }
      }
    });

    // Assigned applications table (sortable)
    var assignedSortCol = 'receiptDate';
    var assignedSortAsc = true;

    function renderAssignedTable() {
      var sorted = assigned.slice().sort(function(a, b) {
        var va, vb;
        if (assignedSortCol === 'age') {
          va = a.receiptDate ? H.daysBetween(a.receiptDate, now) : 0;
          vb = b.receiptDate ? H.daysBetween(b.receiptDate, now) : 0;
        } else if (assignedSortCol === 'receiptDate') {
          va = a.receiptDate ? a.receiptDate.getTime() : 0;
          vb = b.receiptDate ? b.receiptDate.getTime() : 0;
        } else {
          va = (a[assignedSortCol] || '').toLowerCase();
          vb = (b[assignedSortCol] || '').toLowerCase();
        }
        if (va < vb) return assignedSortAsc ? -1 : 1;
        if (va > vb) return assignedSortAsc ? 1 : -1;
        return 0;
      });

      var $abody = $('#fr-assigned-body');
      $abody.empty();
      sorted.forEach(function(a) {
        var age = a.receiptDate ? H.daysBetween(a.receiptDate, now) : 0;
        var ageStyle = age > 90 ? 'color:#ff253a;font-weight:700' : age > 30 ? 'color:#e86e00;font-weight:600' : '';
        $abody.append(
          '<tr>' +
            '<td style="font-weight:600;color:#13418A">' + a.fileNumber + '</td>' +
            '<td>' + (a.callsign || '--') + '</td>' +
            '<td>' + a.name + '</td>' +
            '<td>' + (a.experimentType || '--') + '</td>' +
            '<td>' + H.formatDate(a.receiptDate) + '</td>' +
            '<td style="' + ageStyle + '">' + age + '</td>' +
          '</tr>'
        );
      });
      if (!sorted.length) {
        $abody.append('<tr><td colspan="6" style="text-align:center;color:#888;padding:20px">No assigned applications.</td></tr>');
      }

      // Update sort icons
      $('#fr-assigned-table .fr-sortable .fa').removeClass('fa-sort-asc fa-sort-desc').addClass('fa-sort');
      $('#fr-assigned-table .fr-sortable[data-sort="' + assignedSortCol + '"] .fa')
        .removeClass('fa-sort').addClass(assignedSortAsc ? 'fa-sort-asc' : 'fa-sort-desc');
    }

    $('#fr-assigned-table .fr-sortable').off('click').on('click', function() {
      var col = $(this).data('sort');
      if (assignedSortCol === col) {
        assignedSortAsc = !assignedSortAsc;
      } else {
        assignedSortCol = col;
        assignedSortAsc = true;
      }
      renderAssignedTable();
    });

    renderAssignedTable();
  }

  function exportFridayCSV() {
    var now = new Date();
    var lines = ['Section,File Number,Callsign,Applicant,Status,Experiment Type,Receipt Date,Days Pending,Referral Entity,Referral Status,Application URL,Exhibits URL,Correspondence URL'];

    D.allApps.filter(function(a) { return a.status === CONFIG.STATUS.SUBMITTED; }).forEach(function(a) {
      var age = a.receiptDate ? H.daysBetween(a.receiptDate, now) : 0;
      lines.push([
        '"Submitted"', '"' + a.fileNumber + '"', '"' + (a.callsign || '') + '"',
        '"' + a.name + '"', '"Submitted"', '"' + (a.experimentType || '') + '"',
        a.receiptDate ? H.formatDate(a.receiptDate) : '', age, '', '',
        '"' + (a.applicationUrl || '') + '"',
        '"' + (a.exhibitsUrl || '') + '"',
        '"' + (a.correspondenceUrl || '') + '"'
      ].join(','));
    });

    D.allApps.filter(function(a) { return a.status === CONFIG.STATUS.ASSIGNED; }).forEach(function(a) {
      var age = a.receiptDate ? H.daysBetween(a.receiptDate, now) : 0;
      lines.push([
        '"Assigned"', '"' + a.fileNumber + '"', '"' + (a.callsign || '') + '"',
        '"' + a.name + '"', '"Assigned"', '"' + (a.experimentType || '') + '"',
        a.receiptDate ? H.formatDate(a.receiptDate) : '', age, '', '',
        '"' + (a.applicationUrl || '') + '"',
        '"' + (a.exhibitsUrl || '') + '"',
        '"' + (a.correspondenceUrl || '') + '"'
      ].join(','));
    });

    D.allApps.filter(function(a) { return a.status === CONFIG.STATUS.REFERRED; }).forEach(function(a) {
      a.charges.forEach(function(c) {
        var age = a.receiptDate ? H.daysBetween(a.receiptDate, now) : 0;
        lines.push([
          '"Referred"', '"' + a.fileNumber + '"', '"' + (a.callsign || '') + '"',
          '"' + a.name + '"', '"Referred"', '"' + (a.experimentType || '') + '"',
          a.receiptDate ? H.formatDate(a.receiptDate) : '', age,
          '"' + (c.charge || '') + '"', c.closeDate ? 'Closed' : 'Open',
          '"' + (a.applicationUrl || '') + '"',
          '"' + (a.exhibitsUrl || '') + '"',
          '"' + (a.correspondenceUrl || '') + '"'
        ].join(','));
      });
    });

    var blob = new Blob([lines.join('\n')], { type: 'text/csv' });
    var url = URL.createObjectURL(blob);
    var a = document.createElement('a');
    a.href = url;
    a.download = 'friday-report-' + new Date().toISOString().slice(0, 10) + '.csv';
    a.click();
    URL.revokeObjectURL(url);
  }

  D.updateFridayReport = updateFridayReport;
  D.exportFridayCSV = exportFridayCSV;
})(jQuery);
