import express, { type Application, type Request, type Response } from 'express';
import { logger } from '../logger.js';
import { parseTaskId } from './validation.js';
import { canViewTask, resolveSpaceAccess } from './local-api-helpers.js';
import { type LocalTasksDeps, resolveTaskWriteGate } from './local-tasks-shared.js';

/**
 * Tool-request mechanism: list a task's recorded tool requests, and
 * approve/deny a pending one (granting the tool for the rest of the task).
 */
export function registerLocalTaskToolRequestRoutes(app: Application, deps: LocalTasksDeps): void {
  const { repo } = deps;

  // Tool-request mechanism: list the tool requests recorded for a task
  // (RequestTool declarations + passively-captured blocked calls).
  app.get('/api/local/tasks/:taskId/tool-requests', async (req: Request, res: Response) => {
    try {
      const taskId = parseTaskId(req.params.taskId);
      if (taskId === null) { res.status(400).json({ error: 'Invalid task ID' }); return; }
      const viewer = req.user as Express.User | undefined;
      const task = await repo.getLocalTask(taskId, viewer ? { viewer } : undefined);
      if (!canViewTask(req, res, task, resolveSpaceAccess(repo, task, viewer))) return;
      res.json({ toolRequests: repo.listToolRequestsByTask(String(taskId)) });
    } catch (err) {
      logger.error(`Tool requests list API error: ${err}`);
      res.status(500).json({ error: 'Failed to list tool requests' });
    }
  });

  // Tool-request mechanism: approve (grant for this task + resume) or deny a
  // pending tool request. Requires task write permission (owner / admin /
  // space editor). Approving grants the tool for the rest of THIS task; the
  // permanent fix (adding it to the piece) is a separate one-click action in
  // the piece editor's aggregation view.
  app.post('/api/local/tasks/:taskId/tool-requests/:reqId/decide', express.json(), async (req: Request, res: Response) => {
    try {
      const taskId = parseTaskId(req.params.taskId);
      if (taskId === null) { res.status(400).json({ error: 'Invalid task ID' }); return; }
      const reqId = String(req.params.reqId);
      const decision = (req.body as { decision?: unknown })?.decision;
      if (decision !== 'approve' && decision !== 'deny') {
        res.status(400).json({ error: 'decision must be "approve" or "deny"' });
        return;
      }
      const viewer = req.user as Express.User | undefined;
      const task = await repo.getLocalTask(taskId, viewer ? { viewer } : undefined);
      const gate = await resolveTaskWriteGate(repo, viewer, task ? { ownerId: task.ownerId, spaceId: task.spaceId } : null);
      if (gate !== 'allow') {
        res.status(gate === 'view-only' ? 403 : 404)
          .json({ error: gate === 'view-only' ? 'No permission to decide tool requests' : 'Task not found' });
        return;
      }
      const tr = repo.getToolRequest(reqId);
      if (!tr || tr.taskId !== String(taskId)) { res.status(404).json({ error: 'Tool request not found' }); return; }
      if (tr.status !== 'pending') { res.status(409).json({ error: `Already decided (${tr.status})` }); return; }

      const decidedBy = viewer?.id ?? null;
      if (decision === 'approve') {
        repo.addGrantedTool(String(taskId), tr.toolName);
        repo.decideToolRequest(reqId, { status: 'approved', grantScope: 'task', decidedBy });
      } else {
        repo.decideToolRequest(reqId, { status: 'denied', decidedBy });
      }
      // Resume the parked job so the agent continues (with or without the tool).
      const resumed = tr.jobId ? repo.resumeToolRequestJob(tr.jobId) : 0;
      res.json({ ok: true, decision, toolName: tr.toolName, resumed: resumed > 0 });
    } catch (err) {
      logger.error(`Tool request decide API error: ${err}`);
      res.status(500).json({ error: 'Failed to decide tool request' });
    }
  });
}
