import type { FastifyInstance } from 'fastify';
import { z } from 'zod';
import pino from 'pino';
import { withTenant } from '../data/db.js';
import { AgentBridge } from '../bridge/agent-bridge.js';
import { config } from '../config/index.js';

const logger = pino({ name: 'api-approvals' });
const bridge = new AgentBridge(config.REDIS_URL);

const approvalDecisionSchema = z.object({
  decision: z.enum(['approve', 'reject']),
  reason: z.string().max(500).optional(),
});

export function registerApprovalRoutes(app: FastifyInstance) {
  // List pending approvals for tenant
  app.get('/api/v1/approvals', async (req, reply) => {
    const tenantId = (req as any).tenantId;

    const result = await withTenant(tenantId, async (client) => {
      return client.query(
        `SELECT ae.id, ae.execution_id, ae.step_index, ae.command, ae.safety_level, ae.started_at,
                e.runbook_id, r.name as runbook_name
         FROM audit_entries ae
         JOIN executions e ON ae.execution_id = e.id
         JOIN runbooks r ON e.runbook_id = r.id
         WHERE ae.status = 'awaiting_approval'
         ORDER BY ae.started_at DESC`,
      );
    });

    return { approvals: result.rows };
  });

  // Approve or reject a step
  app.post('/api/v1/approvals/:stepId', async (req, reply) => {
    const { stepId } = req.params as { stepId: string };
    const body = approvalDecisionSchema.parse(req.body);
    const tenantId = (req as any).tenantId;
    const userId = (req as any).userId;

    const result = await withTenant(tenantId, async (client) => {
      // Get the audit entry and its execution
      const entry = await client.query(
        `SELECT ae.id, ae.execution_id, ae.status, e.runbook_id
         FROM audit_entries ae JOIN executions e ON ae.execution_id = e.id
         WHERE ae.id = $1 AND ae.status = 'awaiting_approval'`,
        [stepId],
      );

      if (!entry.rows[0]) return null;

      const newStatus = body.decision === 'approve' ? 'approved' : 'rejected';

      await client.query(
        `UPDATE audit_entries SET status = $1, approved_by = $2, approval_method = 'api'
         WHERE id = $3`,
        [newStatus, userId, stepId],
      );

      // If rejected, abort the execution
      if (body.decision === 'reject') {
        await client.query(
          `UPDATE executions SET status = 'aborted', completed_at = now() WHERE id = $1`,
          [entry.rows[0].execution_id],
        );
      }

      return entry.rows[0];
    });

    if (!result) return reply.status(404).send({ error: 'Pending approval not found' });

    // Notify agent via Redis pub/sub
    await bridge.sendApproval(tenantId, result.execution_id, stepId, body.decision);

    logger.info({ stepId, decision: body.decision, userId }, 'Approval decision recorded');
    return { step_id: stepId, decision: body.decision, reason: body.reason };
  });
}
