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

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

export function registerSlackRoutes(app: FastifyInstance) {
  // Slack Events API verification
  app.post('/slack/events', async (req, reply) => {
    if (config.SLACK_SIGNING_SECRET) {
      const timestamp = req.headers['x-slack-request-timestamp'] as string;
      const signature = req.headers['x-slack-signature'] as string;
      const body = JSON.stringify(req.body);

      if (!verifySlackSignature(body, timestamp, signature, config.SLACK_SIGNING_SECRET)) {
        return reply.status(401).send({ error: 'Invalid signature' });
      }
    }

    const payload = req.body as any;
    if (payload.type === 'url_verification') {
      return { challenge: payload.challenge };
    }

    return { ok: true };
  });

  // Slack interactive components (approve/reject buttons)
  app.post('/slack/interactions', async (req, reply) => {
    const rawPayload = (req.body as any)?.payload;
    if (!rawPayload) return reply.status(400).send({ error: 'Missing payload' });

    let payload: any;
    try {
      payload = JSON.parse(rawPayload);
    } catch {
      return reply.status(400).send({ error: 'Invalid payload' });
    }

    if (payload.type === 'block_actions') {
      for (const action of payload.actions ?? []) {
        const [actionType, stepId] = (action.action_id ?? '').split(':');
        const slackUserId = payload.user?.id ?? 'unknown';

        if (actionType === 'approve_step' && stepId) {
          // Look up the audit entry to get tenant + execution context
          const { pool } = await import('../data/db.js');
          const entry = await pool.query(
            `SELECT ae.id, ae.execution_id, e.tenant_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]) {
            const { tenant_id, execution_id } = entry.rows[0];

            await withTenant(tenant_id, async (client) => {
              await client.query(
                `UPDATE audit_entries SET status = 'approved', approved_by = $1, approval_method = 'slack_button'
                 WHERE id = $2`,
                [slackUserId, stepId],
              );
            });

            await bridge.sendApproval(tenant_id, execution_id, stepId, 'approve');
            logger.info({ stepId, user: slackUserId }, 'Step approved via Slack');
          }
        } else if (actionType === 'reject_step' && stepId) {
          const { pool } = await import('../data/db.js');
          const entry = await pool.query(
            `SELECT ae.id, ae.execution_id, e.tenant_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]) {
            const { tenant_id, execution_id } = entry.rows[0];

            await withTenant(tenant_id, async (client) => {
              await client.query(
                `UPDATE audit_entries SET status = 'rejected', approved_by = $1, approval_method = 'slack_button'
                 WHERE id = $2`,
                [slackUserId, stepId],
              );
              await client.query(
                `UPDATE executions SET status = 'aborted', completed_at = now() WHERE id = $1`,
                [execution_id],
              );
            });

            await bridge.sendApproval(tenant_id, execution_id, stepId, 'reject');
            logger.info({ stepId, user: slackUserId }, 'Step rejected via Slack');
          }
        }
      }
    }

    return { ok: true };
  });
}

function verifySlackSignature(body: string, timestamp: string, signature: string, secret: string): boolean {
  if (!timestamp || !signature) return false;
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - parseInt(timestamp, 10)) > 300) return false;

  const sigBasestring = `v0:${timestamp}:${body}`;
  const expected = 'v0=' + crypto.createHmac('sha256', secret).update(sigBasestring).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
