/**
 * API types generator for ReactAppStarter
 *
 * Emits per-model TypeScript interfaces that the starter's view
 * skeletons import (`import type { Task } from '../types/api'`). The
 * shape mirrors the model's attributes as declared in the spec. No
 * runtime-specific types (those live in ReactAppRuntime's api-types
 * generator).
 */

export interface ApiTypesStarterContext {
  spec: {
    models?: Record<string, any>;
  };
  manifest?: unknown;
}

/**
 * Map SpecVerse attribute types to TypeScript types.
 *
 * Strings vs unions: if the attribute has a `values` enum (e.g.
 * status: String values=[draft,published]), emit a union type.
 */
function mapAttrType(attr: any): string {
  const t = typeof attr === 'string'
    ? attr.split(/\s+/)[0]
    : attr?.type;
  const values = attr?.values;
  if (Array.isArray(values) && values.length > 0) {
    return values.map((v: string) => JSON.stringify(v)).join(' | ');
  }
  switch ((t || '').toLowerCase()) {
    case 'string':
    case 'text':
    case 'uuid':
    case 'email':
    case 'url':
      return 'string';
    case 'int':
    case 'integer':
    case 'float':
    case 'number':
    case 'decimal':
      return 'number';
    case 'boolean':
    case 'bool':
      return 'boolean';
    case 'datetime':
    case 'date':
    case 'time':
    case 'timestamp':
      return 'string';
    case 'json':
      return 'Record<string, unknown>';
    default:
      return 'unknown';
  }
}

function isRequired(attr: any): boolean {
  if (typeof attr === 'string') return /\brequired\b/.test(attr);
  return !!attr?.required;
}

export async function generate(context: ApiTypesStarterContext): Promise<string> {
  const models = context.spec.models ?? {};
  const modelNames = Object.keys(models);

  const header = `/**
 * API types (ReactAppStarter)
 *
 * Per-model interfaces generated from the spec's model definitions.
 * Safe to edit — extend these when your UI needs more than the spec
 * describes (e.g. optimistic fields, denormalized joins).
 */
`;

  const interfaces = modelNames.map(name => {
    const model = models[name] || {};
    const attrs = model.attributes || {};
    const attrKeys = Object.keys(attrs);

    const fields = attrKeys.map(attrName => {
      const attr = attrs[attrName];
      const tsType = mapAttrType(attr);
      const optional = isRequired(attr) ? '' : '?';
      return `  ${attrName}${optional}: ${tsType};`;
    }).join('\n');

    return `export interface ${name} {
${fields || '  [key: string]: unknown;'}
}`;
  }).join('\n\n');

  return header + '\n' + interfaces + '\n';
}

export default generate;
