/**
 * GET /api/rmm/executions
 *   List recent executions. Filters: companyId, scriptId, status,
 *   assetType, assetId. requireAuth() — admin sees all by default.
 *
 * POST /api/rmm/executions
 *   Body: { scriptId, target: { type: 'site_anchor', companyId } |
 *                          { type: 'asset_self', deviceUid, hostname?, companyId?, assetType?, assetId? },
 *           triggeredByAuditId? }
 *   Requires rmm.execute. Queues a fresh execution.
 */

import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
import { requireAuth, requirePermission } from '@/lib/auth-utils';
import {
  listExecutions,
  type RmmExecutionStatus,
} from '@/lib/services/rmm/persistence';
import { queueExecution } from '@/lib/services/rmm/executor';
// Side-effect import: starts the worker once per process.
import '@/lib/services/rmm/worker';

const PostBody = z.object({
  scriptId: z.string().min(1),
  target: z.discriminatedUnion('type', [
    z.object({
      type: z.literal('site_anchor'),
      companyId: z.union([z.string(), z.number()]),
    }),
    z.object({
      type: z.literal('asset_self'),
      deviceUid: z.string().min(1),
      hostname: z.string().nullable().optional(),
      companyId: z.union([z.string(), z.number()]).nullable().optional(),
      assetType: z.enum(['flexible_asset', 'configuration']).optional(),
      assetId: z.union([z.string(), z.number()]).optional(),
    }),
  ]),
  triggeredByAuditId: z.string().uuid().nullable().optional(),
});

const ALLOWED_STATUSES: ReadonlyArray<RmmExecutionStatus> = [
  'queued',
  'running',
  'complete',
  'failed',
  'timeout',
];

export async function GET(request: NextRequest) {
  const { error } = await requireAuth();
  if (error) return error;
  const url = new URL(request.url);
  const limit = Number(url.searchParams.get('limit') ?? 100);
  const offset = Number(url.searchParams.get('offset') ?? 0);
  const companyIdParam = url.searchParams.get('companyId');
  const scriptIdParam = url.searchParams.get('scriptId');
  const statusParam = url.searchParams.get('status');
  const assetTypeParam = url.searchParams.get('assetType');
  const assetIdParam = url.searchParams.get('assetId');
  const status =
    statusParam && ALLOWED_STATUSES.includes(statusParam as RmmExecutionStatus)
      ? (statusParam as RmmExecutionStatus)
      : undefined;
  const assetType =
    assetTypeParam === 'flexible_asset' || assetTypeParam === 'configuration'
      ? assetTypeParam
      : undefined;

  const executions = await listExecutions({
    limit,
    offset,
    companyId: companyIdParam ?? undefined,
    scriptId: scriptIdParam ?? undefined,
    status,
    assetType,
    assetId: assetIdParam ?? undefined,
  });
  return NextResponse.json({ executions });
}

export async function POST(request: NextRequest) {
  const { session, error } = await requirePermission('rmm', 'execute');
  if (error) return error;
  const userId = (session?.user as { id: string } | undefined)?.id ?? null;

  const body = await request.json().catch(() => ({}));
  const parsed = PostBody.safeParse(body);
  if (!parsed.success) {
    return NextResponse.json(
      { error: 'Invalid body', details: parsed.error.issues },
      { status: 400 }
    );
  }

  try {
    const result = await queueExecution({
      scriptId: parsed.data.scriptId,
      target: parsed.data.target,
      performedByUserId: userId,
      triggeredByAuditId: parsed.data.triggeredByAuditId ?? null,
    });
    return NextResponse.json(result);
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    // Rate-limit failures + bad targets read as 400; everything else 500.
    const isClient =
      message.includes('rate limit') ||
      message.includes('No Wulf Nurse') ||
      message.includes('Unknown script') ||
      message.includes('expects target_type');
    return NextResponse.json(
      { error: 'Could not queue execution', message },
      { status: isClient ? 400 : 500 }
    );
  }
}
