/**
 * Phase 2 Slice 14 — Fastify routes-generator extracts _actor from
 * (request as any).user and threads it to every handler.* call site.
 *
 * Pins the actor-wiring contract for the realized backend so the
 * downstream constraint guards (per-model <Model>.guards.ts → runGuards
 * → actor.* paths) actually receive an actor.
 */

import { describe, it, expect } from 'vitest';
import generateFastifyRoutes from '../routes-generator.js';

/** Build a TemplateContext for a Vote controller with the four CURVED ops. */
function voteCtx(): any {
  return {
    controller: {
      name: 'VoteController',
      modelReference: 'Vote',
      cured: { create: true, retrieve: true, update: true, delete: true, validate: true },
    },
    model: { name: 'Vote', attributes: { choice: { type: 'String' } } },
    spec: { name: 'TestSpec', models: { Vote: { name: 'Vote' } } },
    implType: 'prisma',
  };
}

describe('Fastify routes — Slice 14 actor wiring', () => {
  it('extracts _actor from (request as any).user in create handler', () => {
    const out = generateFastifyRoutes(voteCtx());
    expect(out).toContain('(request as any).user');
    expect(out).toMatch(/handler\.create\(request\.body[^,)]*,\s*_actor\)/);
  });

  it('threads _actor through update handler', () => {
    const out = generateFastifyRoutes(voteCtx());
    expect(out).toMatch(/handler\.update\(id,\s*request\.body[^,)]*,\s*_actor\)/);
  });

  it('threads _actor through delete handler', () => {
    const out = generateFastifyRoutes(voteCtx());
    expect(out).toMatch(/handler\.delete\(id,\s*_actor\)/);
  });

  it('threads _actor through validate handler', () => {
    const out = generateFastifyRoutes(voteCtx());
    expect(out).toMatch(/handler\.validate\(data,\s*\{\s*operation:\s*op\s*\},\s*_actor\)/);
  });

  it('extracts _actor exactly once per mutation handler (no duplicate declarations)', () => {
    const out = generateFastifyRoutes(voteCtx());
    // Each mutation handler body has its own `const _actor = ...` line.
    // We expect at least 4 (create, update, delete, validate).
    const decls = (out.match(/const _actor = \(request as any\)\.user/g) || []).length;
    expect(decls).toBeGreaterThanOrEqual(4);
    // retrieve handler exists but does NOT extract _actor (read-only op).
    if (/handler\.retrieve\(id\)/.test(out)) {
      const retrieveBlock = out.substring(
        out.indexOf("// Operation: 'retrieve'") !== -1
          ? out.indexOf("// Operation: 'retrieve'")
          : out.indexOf('handler.retrieve(id)'),
        out.indexOf('handler.retrieve(id)') + 50,
      );
      expect(retrieveBlock).not.toContain('const _actor');
    }
  });

  it('threads _actor through custom action handlers', () => {
    const ctx = voteCtx();
    ctx.controller.actions = {
      cast: {
        path: '/cast',
        method: 'POST',
        parameters: { ballot: { type: 'String', required: true } },
      },
    };
    const out = generateFastifyRoutes(ctx);
    // Custom action handler: handler.cast(args, _actor)
    expect(out).toMatch(/handler\.cast\(args,\s*_actor\)/);
  });
});
