import { Body, Controller, Delete, Get, Inject, Param, Post, UseGuards } from '@nestjs/common';
import type { RoutingCriteria } from '@mosaicstack/types';
import { AuthGuard } from '../auth/auth.guard.js';
import { CurrentUser } from '../auth/current-user.decorator.js';
import { ProviderService } from './provider.service.js';
import { ProviderCredentialsService } from './provider-credentials.service.js';
import { RoutingService } from './routing.service.js';
import type { TestConnectionDto, TestConnectionResultDto } from './provider.dto.js';
import type {
  StoreCredentialDto,
  ProviderCredentialSummaryDto,
} from './provider-credentials.dto.js';

@Controller('api/providers')
@UseGuards(AuthGuard)
export class ProvidersController {
  constructor(
    @Inject(ProviderService) private readonly providerService: ProviderService,
    @Inject(ProviderCredentialsService)
    private readonly credentialsService: ProviderCredentialsService,
    @Inject(RoutingService) private readonly routingService: RoutingService,
  ) {}

  @Get()
  list() {
    return this.providerService.listProviders();
  }

  @Get('models')
  listModels() {
    return this.providerService.listAvailableModels();
  }

  @Get('health')
  health() {
    return { providers: this.safeProviderHealth() };
  }

  /**
   * Safe operational status for troubleshooting and readiness checks. Provider
   * errors are reduced to a stable code so credentials and remote responses
   * cannot leak through this endpoint.
   */
  @Get('status')
  status() {
    return {
      providers: this.safeProviderHealth(),
      effectivePolicy: this.providerService.getEffectivePolicyStatus(),
    };
  }

  @Post('test')
  testConnection(@Body() body: TestConnectionDto): Promise<TestConnectionResultDto> {
    return this.providerService.testConnection(body.providerId, body.baseUrl);
  }

  @Post('route')
  route(@Body() criteria: RoutingCriteria) {
    return this.routingService.route(criteria);
  }

  @Post('rank')
  rank(@Body() criteria: RoutingCriteria) {
    return this.routingService.rank(criteria);
  }

  private safeProviderHealth() {
    return this.providerService.getProvidersHealth().map(({ error, ...provider }) => ({
      ...provider,
      ...(error ? { errorCode: 'provider_unavailable' } : {}),
    }));
  }

  // ── Credential CRUD ──────────────────────────────────────────────────────

  /**
   * GET /api/providers/credentials
   * List all provider credentials for the authenticated user.
   * Returns provider names, types, and metadata — never decrypted values.
   */
  @Get('credentials')
  listCredentials(@CurrentUser() user: { id: string }): Promise<ProviderCredentialSummaryDto[]> {
    return this.credentialsService.listProviders(user.id);
  }

  /**
   * POST /api/providers/credentials
   * Store or update a provider credential for the authenticated user.
   * The value is encrypted before storage and never returned.
   */
  @Post('credentials')
  async storeCredential(
    @CurrentUser() user: { id: string },
    @Body() body: StoreCredentialDto,
  ): Promise<{ success: boolean; provider: string }> {
    await this.credentialsService.store(
      user.id,
      body.provider,
      body.type,
      body.value,
      body.metadata,
    );
    return { success: true, provider: body.provider };
  }

  /**
   * DELETE /api/providers/credentials/:provider
   * Remove a stored credential for the authenticated user.
   */
  @Delete('credentials/:provider')
  async removeCredential(
    @CurrentUser() user: { id: string },
    @Param('provider') provider: string,
  ): Promise<{ success: boolean; provider: string }> {
    await this.credentialsService.remove(user.id, provider);
    return { success: true, provider };
  }
}
