// ─────────────────────────────────────────────────────────────────────────────
// Documents mappers — display metadata and formatters.
// Same shape as my-audits.mappers.ts.
// ─────────────────────────────────────────────────────────────────────────────

import type {
  DocumentAction,
  DocumentStatus,
} from '../types/documents.types';

// ─── Category pill colors ───────────────────────────────────────────────────
// Reused across the table, the upload modal, and the audit log filter.
export const CATEGORY_META: Record<
  string,
  { label: string; bg: string; text: string; icon: string }
> = {
  'ISO Documentation': {
    label: 'ISO Documentation',
    bg: '#ede9fe',
    text: '#5b21b6',
    icon: '📘',
  },
  'Audit Reports': {
    label: 'Audit Reports',
    bg: '#dbeafe',
    text: '#1e40af',
    icon: '📊',
  },
  Marketing: {
    label: 'Marketing',
    bg: '#fce7f3',
    text: '#be185d',
    icon: '📣',
  },
  'HR & Policies': {
    label: 'HR & Policies',
    bg: '#fef3c7',
    text: '#92400e',
    icon: '👥',
  },
  Certificates: {
    label: 'Certificates',
    bg: '#dcfce7',
    text: '#166534',
    icon: '🎓',
  },
};

// Fallback for anything not in the map — keeps the UI stable if a new
// category slips in via the DB before the frontend is redeployed.
export const getCategoryMeta = (category: string) =>
  CATEGORY_META[category] || {
    label: category,
    bg: '#f3f4f6',
    text: '#374151',
    icon: '📄',
  };

// ─── Status pill colors ─────────────────────────────────────────────────────
export const STATUS_CONFIG: Record<
  DocumentStatus,
  { label: string; bg: string; text: string; dot: string }
> = {
  active: {
    label: 'Active',
    bg: '#dcfce7',
    text: '#166534',
    dot: '#22c55e',
  },
  archived: {
    label: 'Archived',
    bg: '#f3f4f6',
    text: '#6b7280',
    dot: '#9ca3af',
  },
};

// ─── Audit-action pill colors (used in AuditLogModal) ───────────────────────
export const ACTION_META: Record<
  DocumentAction,
  { label: string; bg: string; text: string; icon: string }
> = {
  viewed: {
    label: 'Viewed',
    bg: '#dbeafe',
    text: '#1e40af',
    icon: '👁',
  },
  downloaded: {
    label: 'Downloaded',
    bg: '#dcfce7',
    text: '#166534',
    icon: '⬇',
  },
  otp_sent: {
    label: 'OTP sent',
    bg: '#ede9fe',
    text: '#5b21b6',
    icon: '📧',
  },
  otp_failed: {
    label: 'OTP failed',
    bg: '#fef3c7',
    text: '#92400e',
    icon: '⚠',
  },
  password_failed: {
    label: 'Password failed',
    bg: '#fee2e2',
    text: '#991b1b',
    icon: '⚠',
  },
  denied: {
    label: 'Denied',
    bg: '#fee2e2',
    text: '#991b1b',
    icon: '✕',
  },
};

// ─── Security summary — one-line human description ──────────────────────────
export function formatSecuritySummary(doc: {
  password_hash: string | null;
  require_otp: number;
  allow_download: number;
}): string {
  const parts: string[] = [];
  if (doc.require_otp) parts.push('OTP');
  if (doc.password_hash) parts.push('password');
  const lock = parts.length ? `🔒 ${parts.join(' + ')}` : '🔓 open';
  return doc.allow_download ? lock : `${lock} · view-only`;
}

// ─── File-icon meta from mime type ──────────────────────────────────────────
export function fileIconMeta(mime: string | null | undefined): {
  label: string;
  bg: string;
  text: string;
} {
  const m = (mime || '').toLowerCase();
  if (m.includes('pdf')) return { label: 'PDF', bg: '#fee2e2', text: '#dc2626' };
  if (m.includes('word') || m.includes('document'))
    return { label: 'DOC', bg: '#dbeafe', text: '#2563eb' };
  if (m.includes('sheet') || m.includes('excel'))
    return { label: 'XLS', bg: '#dcfce7', text: '#166534' };
  if (m.includes('presentation') || m.includes('powerpoint'))
    return { label: 'PPT', bg: '#fed7aa', text: '#c2410c' };
  if (m.startsWith('image/'))
    return { label: 'IMG', bg: '#ede9fe', text: '#5b21b6' };
  return { label: 'FILE', bg: '#f3f4f6', text: '#374151' };
}

// ─── File-size formatter (bytes → "1.4 MB") ─────────────────────────────────
export function formatFileSize(bytes: number | null | undefined): string {
  if (!bytes || bytes <= 0) return '—';
  const units = ['B', 'KB', 'MB', 'GB'];
  let n = bytes;
  let i = 0;
  while (n >= 1024 && i < units.length - 1) {
    n /= 1024;
    i++;
  }
  return `${n.toFixed(n >= 10 || i === 0 ? 0 : 1)} ${units[i]}`;
}

// ─── Date "12 Aug 26 · 09:14" ───────────────────────────────────────────────
export function formatDateTime(iso: string | Date): string {
  const d = typeof iso === 'string' ? new Date(iso) : iso;
  const day = String(d.getDate()).padStart(2, '0');
  const month = d.toLocaleString('en-US', { month: 'short' });
  const year = String(d.getFullYear()).slice(2);
  const hh = String(d.getHours()).padStart(2, '0');
  const mm = String(d.getMinutes()).padStart(2, '0');
  return `${day} ${month} ${year} · ${hh}:${mm}`;
}

export function formatDate(iso: string | Date | null | undefined): string {
  if (!iso) return '—';
  const d = typeof iso === 'string' ? new Date(iso) : iso;
  const day = String(d.getDate()).padStart(2, '0');
  const month = d.toLocaleString('en-US', { month: 'short' });
  const year = String(d.getFullYear()).slice(2);
  return `${day} ${month} ${year}`;
}

// ─── Expiry helper — returns null if no expiry, else color-coded label ──────
export function expiryHint(expiry: string | null | undefined): {
  label: string;
  color: string;
} | null {
  if (!expiry) return null;
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  const exp = new Date(expiry);
  exp.setHours(0, 0, 0, 0);
  const diff = Math.round(
    (exp.getTime() - today.getTime()) / (1000 * 60 * 60 * 24),
  );
  if (diff < 0) return { label: 'Expired', color: '#dc2626' };
  if (diff === 0) return { label: 'Expires today', color: '#d97706' };
  if (diff <= 7) return { label: `Expires in ${diff}d`, color: '#d97706' };
  if (diff <= 30) return { label: `Expires in ${diff}d`, color: '#6b7280' };
  return { label: `Expires ${formatDate(expiry)}`, color: '#9ca3af' };
}
