/**
 * Base system-prompt rules prepended to every template's prompt before
 * sending to the model. Centralized here so we can tighten output
 * constraints in one place rather than editing every template.
 *
 * Two main jobs:
 *   1. Force the JSON output shape (no prose, no fences, picks library
 *      ids only — fixes "exerciseId doesn't belong to this user" errors)
 *   2. Force a suggested starting weight per resistance exercise
 *      (the model otherwise tends to leave it null, which leaves the
 *      user with no concrete target on day 1)
 *
 * Templates supply their *coaching philosophy* (hypertrophy = volume +
 * progressive overload, conditioning = aerobic base etc); this module
 * supplies the *structural contract*.
 */

export interface BaseSystemPromptOpts {
  /** "lbs" | "kg" — the user's preferred weight unit, used as the default
   *  suggestedWeightUnit when the model omits one. */
  weightUnit: 'lbs' | 'kg';
  /** Whether the user's workout history is being included. Toggles a
   *  short instruction on how to use it. */
  hasHistoryContext: boolean;
  /** True when the model is local (Ollama). Local models tend to need
   *  shorter, blunter rules and benefit from explicit examples. */
  isLocalModel: boolean;
}

export function buildBaseSystemPrompt(opts: BaseSystemPromptOpts): string {
  const lines: string[] = [];

  lines.push(
    '# OUTPUT CONTRACT (mandatory)',
    '',
    '1. Reply with EXACTLY ONE JSON object. No prose before or after. No ```json fences.',
    '2. Every exercise must use an `exerciseId` from the LIBRARY block at the bottom of this prompt. NEVER invent ids. If nothing in the library matches, pick the closest fit and explain the substitution in `notes`.',
    `3. Every resistance exercise MUST have a \`suggestedWeight\` (a number, in ${opts.weightUnit}). Cardio, stretching, and bodyweight exercises set it to null.`,
    `4. \`suggestedWeightUnit\` should be "${opts.weightUnit}" unless the exercise is conventionally tracked in the other unit (e.g. kettlebells often kg). Omit for non-loaded exercises.`,
    '5. Every exercise needs `sets` and either `repsMin` (with `repsMax` if a range) or a duration note.',
    '6. Use `rpe` (1-10) for working sets to communicate intensity; warmups can be lower or omitted.',
    '7. `restSeconds` is required for compound lifts; optional for accessories.',
    '8. Keep day volumes realistic: 4-7 exercises, 60-75 minutes total. Include warm-up sets only if they belong in the program (don\'t list mobility separately unless the user asked).',
    '9. The `notes` field is for coaching cues, tempo, technique reminders — keep it short, one sentence.',
  );

  if (opts.hasHistoryContext) {
    lines.push(
      '',
      '# USING THE HISTORY BLOCK',
      '',
      'The HISTORY block below summarizes the user\'s last 90 days. Use it to:',
      '- Pick `suggestedWeight` near their current working weights, NOT round numbers from nowhere.',
      '- Address any STAGNANT lifts: deload, change rep ranges, swap variations, or work at a different RPE.',
      '- Respect their training frequency (don\'t prescribe 5x/week if they\'ve been training 3x).',
      '- Stay in their movement vocabulary unless they asked for variety.',
    );
  } else {
    lines.push(
      '',
      '# WEIGHT GUIDANCE WITHOUT HISTORY',
      '',
      `Without prior performance data, set conservative \`suggestedWeight\` values: 50-65% of typical 1RM for the lift at the user's stated experience level. Use round increments common in commercial gyms (5${opts.weightUnit} jumps; 2.5${opts.weightUnit} for small accessories). Always add a coaching note like "adjust to leave 2-3 reps in reserve" so the user knows it's a starting estimate.`,
    );
  }

  if (opts.isLocalModel) {
    lines.push(
      '',
      '# LOCAL MODEL REMINDER',
      '',
      'You are running locally with limited reasoning. Stick to the simplest valid program that matches the request. Do not overthink. JSON only.',
    );
  }

  return lines.join('\n');
}
