/**
 * Scaffold Controller for SentryAgent.ai AgentIdP.
 * HTTP handler for the GET /sdk/scaffold/:agentId endpoint.
 */

import { Request, Response, NextFunction } from 'express';
import { AgentRepository } from '../repositories/AgentRepository.js';
import { CredentialRepository } from '../repositories/CredentialRepository.js';
import { AuditService } from '../services/AuditService.js';
import { ScaffoldService, SCAFFOLD_LANGUAGES } from '../services/ScaffoldService.js';
import { ScaffoldLanguage } from '../types/scaffold.js';
import { AgentNotFoundError, AuthorizationError, ValidationError } from '../utils/errors.js';

/**
 * Controller for the scaffold generator endpoint.
 * Validates request, fetches agent credentials, delegates ZIP generation to ScaffoldService.
 */
export class ScaffoldController {
  /**
   * @param scaffoldService - The scaffold generation service.
   * @param agentRepo - Agent repository for agent lookup.
   * @param credentialRepo - Credential repository for active credential lookup.
   * @param auditService - Audit log service.
   */
  constructor(
    private readonly scaffoldService: ScaffoldService,
    private readonly agentRepo: AgentRepository,
    private readonly credentialRepo: CredentialRepository,
    private readonly auditService: AuditService,
  ) {}

  /**
   * Handles GET /sdk/scaffold/:agentId — generates and streams a scaffold ZIP.
   *
   * @param req - Express request with agentId path param and language query param.
   * @param res - Express response streaming the ZIP file.
   * @param next - Express next function.
   */
  getScaffold = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.user) {
        throw new AuthorizationError();
      }

      const { agentId } = req.params;
      const rawLanguage = req.query['language'] as string | undefined;
      const language: ScaffoldLanguage = (rawLanguage as ScaffoldLanguage) ?? 'typescript';

      if (!SCAFFOLD_LANGUAGES.includes(language)) {
        throw new ValidationError(
          `Unsupported language '${language}'. Choose: ${SCAFFOLD_LANGUAGES.join(', ')}`,
          { code: 'INVALID_LANGUAGE' },
        );
      }

      const tenantId = req.user.organization_id ?? 'org_system';

      // Fetch agent and verify it belongs to the authenticated tenant
      const agent = await this.agentRepo.findById(agentId);

      if (agent === null) {
        throw new AgentNotFoundError(agentId);
      }

      if (agent.organizationId !== tenantId) {
        throw new AuthorizationError('You do not own this agent.');
      }

      // Fetch the agent's active credential client_id
      const activeClientId = await this.credentialRepo.findActiveClientId(agentId);
      const clientId = activeClientId ?? agentId;

      const apiUrl = process.env['API_URL'] ?? process.env['NEXT_PUBLIC_API_URL'] ?? 'https://api.sentryagent.ai';

      const { stream, filename } = await this.scaffoldService.generateScaffold({
        agentId,
        agentName: agent.email.split('@')[0] ?? agentId,
        clientId,
        language,
        apiUrl,
      });

      const ipAddress = req.ip ?? '0.0.0.0';
      const userAgent = req.headers['user-agent'] ?? 'unknown';

      await this.auditService.logEvent(
        req.user.sub,
        'scaffold.generated',
        'success',
        ipAddress,
        userAgent,
        { agentId, language },
        tenantId,
      );

      res.setHeader('Content-Type', 'application/zip');
      res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);

      stream.pipe(res);
    } catch (err) {
      next(err);
    }
  };
}
