/**
 * ORAC `orac_assessments_status`: 1 Not Started → 3 InProgress (executor) → 5 “Varification Required”
 * (executor submitted to verifier) ↔ 4 Returned until 2 Complete.
 *
 * Verifier UI uses `orac_verification_flow`: `vf_max_occurrence` (max `occurrence` per assessment from API).
 * While status is 5 and `vf_max_occurrence < 1` (no flow row yet), the verifier bucket is **not started**;
 * once `vf_max_occurrence >= 1`, verifier buckets follow `assessment_status_id` as usual (5 → in_process).
 *
 * Other verifier buckets: 1 + 3 → not started; 2 done; 4 returned.
 */
export function getAssessmentStatusLabel(row) {
  return row.assessment_status_name || `Status ${row.assessment_status_id}`;
}

/** Max `occurrence` in `orac_verification_flow` for this assessment (API: `vf_max_occurrence`). */
function getVfMaxOccurrence(row) {
  const raw = row?.vf_max_occurrence;
  if (raw == null || raw === '') return 0;
  const n = Number(raw);
  return Number.isFinite(n) ? n : 0;
}

/**
 * @param {object} row
 * @param {{ forVerifier?: boolean }} [options] — verifier-specific labels for ids 2, 4, 5 (and 3).
 */
export function getAssignmentStatusDisplayLabel(row, options = {}) {
  const forVerifier = options.forVerifier === true;
  const id = Number(row?.assessment_status_id);
  if (forVerifier && id === 5 && getVfMaxOccurrence(row) < 1) {
    return 'Not started';
  }
  if (Number.isInteger(id)) {
    switch (id) {
      case 1:
        return 'Not started';
      case 2:
        return forVerifier ? 'Done' : 'Complete';
      case 3:
        return forVerifier ? 'With executor' : 'In progress';
      case 4:
        return forVerifier ? 'Returned to executor' : 'Returned';
      case 5:
        return forVerifier ? 'Resubmitted by executor' : 'Submit to verifier';
      default:
        break;
    }
  }
  const raw = getAssessmentStatusLabel(row);
  return String(raw).replace(/\bVarification\b/gi, 'Verification');
}

/**
 * Same workflow state for both roles: verifier has sent the assessment back to the executor
 * (DB may label it "Returned", "Return to executor", "Returned to executor", etc.).
 */
export function isReturnedWaitingOnExecutor(row) {
  const l = getAssessmentStatusLabel(row).toLowerCase();
  if (l.includes('returned')) return true;
  if (l.includes('return') && l.includes('executor')) return true;
  return false;
}

/** Verifier sent work back — executor “Returned” bucket (alias). */
export function isReturnByVerifier(row) {
  return isReturnedWaitingOnExecutor(row);
}

/** Verifier dashboard — “Return to Executor” bucket (alias). */
export function isReturnToExecutor(row) {
  return isReturnedWaitingOnExecutor(row);
}

/** DB may spell “Verification” as “Varification” — match both + numeric id */
function isVerificationRequiredStatus(row, normalizedLabel) {
  if (row.assessment_status_id === 5) return true;
  const l = normalizedLabel;
  if (l.includes('varific')) return true;
  return l.includes('verif') && l.includes('requir');
}

export function categorizeExecutorRow(row) {
  const l = getAssessmentStatusLabel(row).toLowerCase();
  if (isReturnByVerifier(row)) return 'returned';
  if (isVerificationRequiredStatus(row, l)) return 'verification_required';
  if (l.includes('complete') || l.includes('done')) return 'done';
  // Executor UI has no separate "In process" bucket — fold into Not started.
  if (l.includes('progress') || l.includes('ongoing') || l.includes('in process')) return 'not_started';
  if (row.assessment_status_id === 3) return 'not_started';
  if (l.includes('not started') || row.assessment_status_id === 1) return 'not_started';
  return 'other';
}

export function categorizeVerifierRow(row) {
  const id = Number(row?.assessment_status_id);
  /**
   * `orac_verification_flow`: until `vf_max_occurrence` is at least 1, the verifier has not
   * started the verification cycle for this submission; bucket as not started. After that,
   * buckets follow `assessment_status_id` (and labels) as usual.
   */
  if (id === 5 && getVfMaxOccurrence(row) < 1) {
    return 'not_started';
  }
  /** Verifier: 1 + 3 → not started (same card); 2 done; 4 returned; 5 resubmitted (in_process bucket). */
  if (Number.isInteger(id)) {
    if (id === 1 || id === 3) return 'not_started';
    if (id === 2) return 'done';
    if (id === 4) return 'returned';
    if (id === 5) return 'in_process';
  }
  const l = getAssessmentStatusLabel(row).toLowerCase();
  if (isReturnToExecutor(row)) return 'returned';
  if (isVerificationRequiredStatus(row, l)) return 'in_process';
  if (l.includes('complete') || l.includes('done')) return 'done';
  if (l.includes('progress') || l.includes('ongoing') || l.includes('in process')) return 'not_started';
  if (l.includes('not started')) return 'not_started';
  return 'other';
}

/**
 * Maps each `assessment_status_id` from the API status list to a dashboard bucket,
 * so counts match server-defined status names even when row joins omit the name.
 */
export function buildCategoryMapsFromStatuses(statuses) {
  const executorMap = new Map();
  const verifierMap = new Map();
  if (!Array.isArray(statuses)) return { executorMap, verifierMap };

  for (const s of statuses) {
    const id = Number(s.assessment_status_id);
    if (Number.isNaN(id)) continue;
    const fake = {
      assessment_status_id: id,
      assessment_status_name: s.assessment_status_name
    };
    executorMap.set(id, categorizeExecutorRow(fake));
    verifierMap.set(id, categorizeVerifierRow(fake));
  }
  return { executorMap, verifierMap };
}

/**
 * @param {Map<number, string>|null|undefined} statusIdToCategory — from `buildCategoryMapsFromStatuses`
 */
export function countByCategory(rows, categorizeFn, statusIdToCategory) {
  const counts = {
    done: 0,
    in_process: 0,
    not_started: 0,
    verification_required: 0,
    returned: 0,
    other: 0
  };
  for (const row of rows) {
    const id = row.assessment_status_id;
    let c;
    if (statusIdToCategory != null && id != null && statusIdToCategory.has(Number(id))) {
      c = statusIdToCategory.get(Number(id));
    } else {
      c = categorizeFn(row);
    }
    counts[c] = (counts[c] || 0) + 1;
  }
  return counts;
}
