import { OAuthRevokeTokenHandler, type OAuthRevokeTokenResponse } from '@app/o-auth/flows';
import { oAuthParseBasicAuth } from '@app/o-auth/shared';
import {
  Body,
  Controller,
  Header,
  Headers,
  HttpCode,
  Post,
  UnsupportedMediaTypeException,
  UseGuards,
} from '@nestjs/common';
import { Throttle, ThrottlerGuard } from '@nestjs/throttler';

const THROTTLE_LIMIT = Number(process.env.THROTTLE_OAUTH_TOKEN_LIMIT ?? 5);
const THROTTLE_TTL_MS = Number(process.env.THROTTLE_OAUTH_TOKEN_TTL_MS ?? 60_000);

/**
 * REST endpoint `POST /api/o-auth/revoke` per RFC 7009 (OAuth2 Token Revocation). Pure
 * transport layer:
 *   - Enforces `application/x-www-form-urlencoded` (RFC 7009 §2.1 wire format).
 *   - Decodes HTTP Basic client credentials (RFC 6749 §2.3.1 transport encoding).
 *   - Reads the `token` + optional `token_type_hint` form parameters.
 *
 * ALL business logic — client authentication, presence validation, revocation — lives in
 * `OAuthRevokeTokenHandler`. The controller passes empty strings for missing fields and lets
 * the handler raise the RFC 6749 §5.2 errors. Per RFC 7009 §2.2 the endpoint answers 200 even
 * for unknown tokens (idempotent, non-enumerable). External integrations should prefer this
 * REST endpoint; the Aurora frontend uses the GraphQL twin `oAuthRevokeToken`.
 *
 * See skill `catalyst-handler-composer` → "Composite handlers" section.
 */
@Controller('o-auth')
export class OAuthRevokeTokenController {
  constructor(private readonly handler: OAuthRevokeTokenHandler) {}

  @Post('revoke')
  @HttpCode(200)
  @UseGuards(ThrottlerGuard)
  @Throttle({ default: { limit: THROTTLE_LIMIT, ttl: THROTTLE_TTL_MS } })
  // RFC 7009 §2.2 — revocation responses must not be cached by intermediaries.
  @Header('Cache-Control', 'no-store')
  @Header('Pragma', 'no-cache')
  async main(
    @Headers('authorization') authorization: string | undefined,
    @Headers('content-type') contentType: string | undefined,
    @Body() body: Record<string, unknown>,
  ): Promise<OAuthRevokeTokenResponse> {
    if (!contentType || !contentType.toLowerCase().includes('application/x-www-form-urlencoded')) {
      // Pure HTTP concern: the wire format requirement. NOT an RFC 6749 §5.2 OAuth error.
      throw new UnsupportedMediaTypeException();
    }

    const { clientId, clientSecret } = oAuthParseBasicAuth(authorization);
    return this.handler.main({
      clientId,
      clientSecret,
      token: typeof body.token === 'string' ? body.token : '',
      tokenTypeHint: typeof body.token_type_hint === 'string' ? body.token_type_hint : undefined,
    });
  }
}
