function generateSharedUtils(context) {
  const files = [
    { path: "field-helpers.ts", content: generateFieldHelpers() },
    { path: "view-helpers.tsx", content: generateViewHelpers() }
  ];
  return { files };
}
function generateFieldHelpers() {
  return `/**
 * Field Helpers \u2014 shared utilities for field classification and display
 * Generated by SpecVerse React factory
 */

const METADATA_FIELDS = new Set([
  'id', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy', 'deletedAt', 'version'
]);

const AUTO_PATTERNS = new Set(['now', 'uuid4', 'autoincrement', 'auto']);

/**
 * Check if a field is auto-generated (should be hidden from forms)
 */
export function isAutoField(name: string, attr: any): boolean {
  if (attr?.auto && AUTO_PATTERNS.has(attr.auto)) return true;
  if (name === 'id') return true;
  if (METADATA_FIELDS.has(name) && attr?.type?.toLowerCase().includes('date')) return true;
  return false;
}

/**
 * Check if a field is metadata (shown last, styled muted)
 */
export function isMetadataField(name: string): boolean {
  return METADATA_FIELDS.has(name);
}

/**
 * Get the best display name for an entity
 * Searches common name fields in priority order
 */
export function getEntityDisplayName(entity: any): string {
  if (!entity) return 'Unknown';
  const METADATA = new Set(['id', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy', 'deletedAt', 'version']);
  // Check common name fields first
  for (const field of ['name', 'title', 'displayName', 'label', 'username', 'email', 'subject', 'message', 'description']) {
    if (entity[field]) return String(entity[field]);
  }
  // Fall back to first non-metadata string value
  for (const [key, val] of Object.entries(entity)) {
    if (!METADATA.has(key) && val && typeof val === 'string' && !String(val).match(/^[0-9a-f-]{36}$/i)) {
      return String(val);
    }
  }
  return entity.id ? String(entity.id).slice(0, 8) + '...' : 'Unknown';
}

/**
 * Classify attributes into ordered groups for display
 */
export function classifyFields(attributes: Array<{ name: string; type: string; auto?: string; required?: boolean }>): {
  business: typeof attributes;
  lifecycle: typeof attributes;
  metadata: typeof attributes;
} {
  const business: typeof attributes = [];
  const lifecycle: typeof attributes = [];
  const metadata: typeof attributes = [];

  for (const attr of attributes) {
    if (isAutoField(attr.name, attr) || isMetadataField(attr.name)) {
      metadata.push(attr);
    } else if (attr.name === 'status' || attr.name === 'state' || attr.name === 'phase') {
      lifecycle.push(attr);
    } else {
      business.push(attr);
    }
  }

  return { business, lifecycle, metadata };
}
`;
}
function generateViewHelpers() {
  return `/**
 * View Helpers \u2014 formatting, colors, and UI utilities
 * Generated by SpecVerse React factory
 */

/**
 * Format a value for display
 */
export function formatValue(value: any, type?: string): string {
  if (value === null || value === undefined) return '\u2014';
  if (type?.toLowerCase().includes('date') || type?.toLowerCase().includes('timestamp')) {
    return formatDate(value);
  }
  if (typeof value === 'boolean') return value ? 'Yes' : 'No';
  return String(value);
}

/**
 * Format a date for display (relative for recent, absolute for old)
 */
export function formatDate(value: any): string {
  if (!value) return '\u2014';
  const date = new Date(value);
  if (isNaN(date.getTime())) return String(value);

  const now = new Date();
  const diff = now.getTime() - date.getTime();
  const minutes = Math.floor(diff / 60000);
  const hours = Math.floor(diff / 3600000);
  const days = Math.floor(diff / 86400000);

  if (minutes < 1) return 'just now';
  if (minutes < 60) return \`\${minutes}m ago\`;
  if (hours < 24) return \`\${hours}h ago\`;
  if (days < 7) return \`\${days}d ago\`;
  return date.toLocaleDateString();
}

/**
 * Truncate text with ellipsis
 */
export function truncate(text: string, max: number = 60): string {
  if (!text || text.length <= max) return text;
  return text.slice(0, max) + '...';
}

/**
 * Get a Tailwind color class for a lifecycle status
 */
export function statusColor(status: string): { bg: string; text: string; dot: string } {
  const s = status?.toLowerCase().replace(/[_-]/g, '') || '';

  // Green states
  if (['active', 'done', 'completed', 'approved', 'published', 'resolved'].includes(s)) {
    return { bg: 'bg-green-50', text: 'text-green-700', dot: 'bg-green-500' };
  }
  // Blue states
  if (['inprogress', 'processing', 'review', 'pending'].includes(s)) {
    return { bg: 'bg-blue-50', text: 'text-blue-700', dot: 'bg-blue-500' };
  }
  // Yellow states
  if (['draft', 'todo', 'planning', 'waiting', 'scheduled'].includes(s)) {
    return { bg: 'bg-yellow-50', text: 'text-yellow-700', dot: 'bg-yellow-500' };
  }
  // Red states
  if (['cancelled', 'rejected', 'failed', 'overdue', 'blocked'].includes(s)) {
    return { bg: 'bg-red-50', text: 'text-red-700', dot: 'bg-red-500' };
  }
  // Gray states
  if (['archived', 'closed', 'deprecated', 'inactive', 'disabled'].includes(s)) {
    return { bg: 'bg-gray-50', text: 'text-gray-500', dot: 'bg-gray-400' };
  }
  // Default: indigo
  return { bg: 'bg-indigo-50', text: 'text-indigo-700', dot: 'bg-indigo-500' };
}

/**
 * StatusBadge component \u2014 matches app-demo's lifecycle badge styling
 */
export function StatusBadge({ status, variant = 'default' }: { status: string; variant?: 'default' | 'lifecycle' }) {
  if (!status) return null;

  // Lifecycle badges use purple (matching app-demo)
  if (variant === 'lifecycle') {
    return (
      <span className="px-2 py-1 bg-purple-100 text-purple-700 rounded text-xs font-medium">
        {status.replace(/[_-]/g, ' ')}
      </span>
    );
  }

  const colors = statusColor(status);
  return (
    <span className={\`inline-flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium \${colors.bg} \${colors.text}\`}>
      <span className={\`w-1.5 h-1.5 rounded-full \${colors.dot}\`}></span>
      {status.replace(/[_-]/g, ' ')}
    </span>
  );
}
`;
}
export {
  generateSharedUtils as default
};
