Source: 20-migration.js

// ── 20-migration.js — Monthly Migration close-out flow ──

let _migItems = [];
let _migIdx = 0;

/**
 * Returns the migration completion record (map of YYYY-MM → boolean).
 * @returns {Object}
 */
function getMigrationRecord() {
  try {
    return JSON.parse(localStorage.getItem(STORE_MIGRATION) || '{}');
  } catch (e) {
    return {};
  }
}

/**
 * Persists the migration completion record to localStorage.
 * @param {Object} rec - Map of YYYY-MM → boolean.
 */
function saveMigrationRecord(rec) {
  localStorage.setItem(STORE_MIGRATION, JSON.stringify(rec));
}

/**
 * Opens the migration modal and populates it with open (unresolved) tasks
 * for the current month.  Alerts if there is nothing to migrate.
 */
function openMigration() {
  const now = new Date();
  const y = now.getFullYear();
  const m = now.getMonth();
  const prefix = `${y}-${String(m + 1).padStart(2, '0')}`;

  _migItems = planTasks.filter(
    (t) => t.date.startsWith(prefix) && t.status !== 'done' && !t._migrated
  );
  _migIdx = 0;

  if (!_migItems.length) {
    wlLog.info('openMigration: nothing to migrate', { monthPrefix: prefix });
    alert('No open tasks to migrate — month is already clean!');
    return;
  }
  wlLog.info('openMigration: opening', { monthPrefix: prefix, taskCount: _migItems.length });

  const overlay = document.getElementById('migrationOverlay');
  if (!overlay) return;

  document.getElementById('migrationTitle').textContent =
    new Date(y, m, 1).toLocaleString('default', { month: 'long', year: 'numeric' }) + ' close-out';
  overlay.style.display = 'flex';
  renderMigrationStep();
}

/** Closes the migration overlay. */
function closeMigration() {
  const overlay = document.getElementById('migrationOverlay');
  if (overlay) overlay.style.display = 'none';
}

/**
 * Renders the current migration step (or the "done" screen when all resolved).
 */
function renderMigrationStep() {
  const total = _migItems.length;
  const counter = document.getElementById('migrationCounter');
  const prog = document.getElementById('migrationProgress');
  const body = document.getElementById('migrationBody');
  if (!body) return;

  if (counter) counter.textContent = `${_migIdx} / ${total} resolved`;
  if (prog) prog.style.width = `${(_migIdx / total) * 100}%`;

  if (_migIdx >= total) {
    body.innerHTML = `
      <div class="mig-done">
        <div class="mig-done-icon">✓</div>
        <div class="mig-done-title">Month closed</div>
        <div class="mig-done-sub">${total} item${total === 1 ? '' : 's'} resolved</div>
      </div>`;
    return;
  }

  const item = _migItems[_migIdx];
  const cat = getCat(item.tag);
  body.innerHTML = `
    <div class="mig-item">
      <div class="mig-item-header">
        <span class="mig-dot" style="background:${safeCssColor(cat.color)}"></span>
        <span class="mig-item-text">${escHtml(item.text)}</span>
      </div>
      <div class="mig-item-date">Added ${item.date}</div>
    </div>
    <div class="mig-actions">
      <button class="mig-btn mig-carry"    id="migCarry">→ Carry forward</button>
      <button class="mig-btn mig-schedule" id="migSchedule">📅 Schedule</button>
      <button class="mig-btn mig-drop"     id="migDrop">✗ Drop</button>
    </div>
    <div id="migDateRow" style="display:none;gap:8px;margin-top:8px;align-items:center">
      <input type="date" class="capture-input" id="migDatePicker"
             style="flex:1" />
      <button class="add-btn" id="migDateConfirm">Confirm date</button>
    </div>`;

  document.getElementById('migCarry').addEventListener('click', () => {
    carryMigTask(_migItems[_migIdx]);
    _migIdx++;
    renderMigrationStep();
  });
  document.getElementById('migSchedule').addEventListener('click', () => {
    const row = document.getElementById('migDateRow');
    if (row) row.style.display = 'flex';
  });
  document.getElementById('migDateConfirm').addEventListener('click', () => {
    const d = document.getElementById('migDatePicker').value;
    if (!d) return;
    scheduleMigTask(_migItems[_migIdx], d);
    _migIdx++;
    renderMigrationStep();
  });
  document.getElementById('migDrop').addEventListener('click', () => {
    dropMigTask(_migItems[_migIdx]);
    _migIdx++;
    renderMigrationStep();
  });
}

/**
 * Duplicates the task into next month (first day) and marks original as migrated.
 * @param {Object} task
 */
function carryMigTask(task) {
  const nextMonth = new Date();
  nextMonth.setDate(1);
  nextMonth.setMonth(nextMonth.getMonth() + 1);
  const targetDate = dk(nextMonth);
  const newTask = {
    ...task,
    id: Date.now() + Math.random().toString(36).slice(2),
    date: targetDate,
    _migrated: false,
  };
  task._migrated = true;
  planTasks.push(newTask);
  savePlan();
  wlLog.info('migration: carried task forward', { fromId: task.id, toDate: targetDate });
}

/**
 * Reschedules the task to the given date and marks it as migrated.
 * @param {Object} task
 * @param {string} dateStr - YYYY-MM-DD
 */
function scheduleMigTask(task, dateStr) {
  task.date = dateStr;
  task._migrated = true;
  savePlan();
  wlLog.info('migration: scheduled task', { id: task.id, newDate: dateStr });
}

/**
 * Archives (drops) the task by marking it done and migrated.
 * @param {Object} task
 */
function dropMigTask(task) {
  task._migrated = true;
  task.status = 'done';
  task.completedAt = Date.now();
  savePlan();
  wlLog.info('migration: dropped task', { id: task.id });
}

/**
 * Initialises the migration overlay: wires close button and optionally shows
 * a last-day-of-month banner once per month.
 */
function initMigration() {
  document.getElementById('migrationClose')?.addEventListener('click', closeMigration);

  // Auto-prompt on last day of month (once per month)
  const now = new Date();
  const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate();
  const isLastDay = now.getDate() === lastDay;
  const rec = getMigrationRecord();
  const monthKey = dk(now).slice(0, 7); // YYYY-MM

  if (isLastDay && !rec[monthKey]) {
    wlLog.info('initMigration: showing last-day banner', { monthKey });
    setTimeout(() => {
      const banner = document.createElement('div');
      banner.className = 'mig-banner';
      banner.id = 'migBanner';
      banner.innerHTML = `📋 Last day of the month — <button id="migBannerBtn">run Migration</button> to close out open tasks.`;
      document.body.prepend(banner);
      document.getElementById('migBannerBtn')?.addEventListener('click', () => {
        banner.remove();
        rec[monthKey] = true;
        saveMigrationRecord(rec);
        openMigration();
      });
    }, 2000);
  } else {
    wlLog.info('initMigration: no auto-prompt', {
      isLastDay,
      alreadyDoneThisMonth: !!rec[monthKey],
    });
  }
}