/**
 * OIDCTrustPolicyController — request handlers for OIDC trust policy management.
 *
 * Handlers:
 *   POST   /oidc/trust-policies                     → createTrustPolicy
 *   GET    /oidc/trust-policies?agentId=<uuid>      → listTrustPolicies
 *   DELETE /oidc/trust-policies/:id                 → deleteTrustPolicy
 */

import { Request, Response, NextFunction } from 'express';
import { OIDCTrustPolicyService } from '../services/OIDCTrustPolicyService.js';
import { ICreateTrustPolicyRequest, OIDCProvider } from '../types/oidc.js';
import { ValidationError } from '../utils/errors.js';

/**
 * Controller for OIDC trust policy endpoints.
 * Delegates all business logic to OIDCTrustPolicyService.
 */
export class OIDCTrustPolicyController {
  /**
   * @param trustPolicyService - Service managing OIDC trust policies.
   */
  constructor(private readonly trustPolicyService: OIDCTrustPolicyService) {}

  // ─────────────────────────────────────────────────────────────────────────
  // Public handlers
  // ─────────────────────────────────────────────────────────────────────────

  /**
   * Creates a new OIDC trust policy.
   *
   * Validates the request body and delegates to OIDCTrustPolicyService.
   * Responds 201 with the created IOIDCTrustPolicy on success.
   * Responds 400 if required fields are missing or invalid.
   * Responds 404 if the referenced agent does not exist.
   *
   * @param req - Express request. Body must conform to ICreateTrustPolicyRequest.
   * @param res - Express response.
   * @param next - Express next function — forwards errors to the global error handler.
   */
  async createTrustPolicy(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const body = req.body as Partial<ICreateTrustPolicyRequest>;

      if (!body.provider || !body.repository || !body.agentId) {
        throw new ValidationError(
          'provider, repository, and agentId are required fields.',
          { received: Object.keys(body) },
        );
      }

      const request: ICreateTrustPolicyRequest = {
        provider: body.provider as OIDCProvider,
        repository: body.repository,
        branch: body.branch,
        agentId: body.agentId,
      };

      const policy = await this.trustPolicyService.createTrustPolicy(request);
      res.status(201).json(policy);
    } catch (err) {
      next(err);
    }
  }

  /**
   * Lists all OIDC trust policies for a given agent.
   *
   * Requires `agentId` as a query parameter.
   * Responds 200 with an array of IOIDCTrustPolicy objects.
   * Responds 400 if agentId is missing.
   *
   * @param req - Express request. `req.query.agentId` must be present.
   * @param res - Express response.
   * @param next - Express next function — forwards errors to the global error handler.
   */
  async listTrustPolicies(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { agentId } = req.query;

      if (typeof agentId !== 'string' || agentId.trim().length === 0) {
        throw new ValidationError('agentId query parameter is required.');
      }

      const policies = await this.trustPolicyService.listTrustPoliciesForAgent(agentId.trim());
      res.status(200).json(policies);
    } catch (err) {
      next(err);
    }
  }

  /**
   * Deletes an OIDC trust policy by its UUID.
   *
   * Responds 204 No Content on success.
   * Responds 404 if no policy with the given ID exists.
   *
   * @param req - Express request. `req.params.id` must be the policy UUID.
   * @param res - Express response.
   * @param next - Express next function — forwards errors to the global error handler.
   */
  async deleteTrustPolicy(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      await this.trustPolicyService.deleteTrustPolicy(id);
      res.status(204).send();
    } catch (err) {
      next(err);
    }
  }
}
