/**
 * Webhooks Controller
 *
 * REST API endpoints for managing webhooks
 */

import {
  Controller,
  Get,
  Post,
  Patch,
  Delete,
  Body,
  Param,
  UseGuards,
  NotFoundException,
  ForbiddenException,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
import { WebhookService, CreateWebhookInput } from '../services/webhook.service';
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
import { RolesGuard } from '../guards/roles.guard';
import { Roles } from '../decorators/roles.decorator';
import { CurrentUser, UserPayload } from '../decorators/current-user.decorator';
import { Webhook, WebhookEvent } from '@domain/entities/webhook.entity';

class CreateWebhookDto {
  url: string;
  events: WebhookEvent[];
  description?: string;
  headers?: Record<string, string>;
}

class UpdateWebhookDto {
  url?: string;
  events?: WebhookEvent[];
  description?: string;
  headers?: Record<string, string>;
}

class WebhookResponseDto {
  id: string;
  url: string;
  events: WebhookEvent[];
  status: string;
  description?: string;
  headers?: Record<string, string>;
  retryCount: number;
  lastTriggeredAt?: string;
  failureCount: number;
  createdAt: string;
  updatedAt: string;
}

@ApiTags('Webhooks')
@ApiBearerAuth()
@Controller('webhooks')
@UseGuards(JwtAuthGuard, RolesGuard)
export class WebhooksController {
  constructor(private readonly webhookService: WebhookService) {}

  /**
   * Create a new webhook
   * Only admins and managers can create webhooks
   */
  @Post()
  @Roles('admin', 'manager')
  @ApiOperation({ summary: 'Create a new webhook' })
  @ApiResponse({ status: 201, description: 'Webhook created successfully' })
  async createWebhook(
    @Body() dto: CreateWebhookDto,
    @CurrentUser() user: UserPayload
  ): Promise<WebhookResponseDto> {
    const input: CreateWebhookInput = {
      organizationId: user.organizationId,
      url: dto.url,
      events: dto.events,
      description: dto.description,
      headers: dto.headers,
    };

    const webhook = await this.webhookService.createWebhook(input);
    return this.mapToDto(webhook);
  }

  /**
   * Get all webhooks for organization
   */
  @Get()
  @Roles('admin', 'manager')
  @ApiOperation({ summary: 'Get all webhooks for organization' })
  @ApiResponse({ status: 200, description: 'Webhooks retrieved successfully' })
  async getWebhooks(@CurrentUser() user: UserPayload): Promise<WebhookResponseDto[]> {
    const webhooks = await this.webhookService.getWebhooksByOrganization(user.organizationId);
    return webhooks.map(w => this.mapToDto(w));
  }

  /**
   * Get webhook by ID
   */
  @Get(':id')
  @Roles('admin', 'manager')
  @ApiOperation({ summary: 'Get webhook by ID' })
  @ApiResponse({ status: 200, description: 'Webhook retrieved successfully' })
  @ApiResponse({ status: 404, description: 'Webhook not found' })
  async getWebhookById(
    @Param('id') id: string,
    @CurrentUser() user: UserPayload
  ): Promise<WebhookResponseDto> {
    const webhook = await this.webhookService.getWebhookById(id);

    if (!webhook) {
      throw new NotFoundException('Webhook not found');
    }

    // Verify webhook belongs to user's organization
    if (webhook.organizationId !== user.organizationId) {
      throw new ForbiddenException('Access denied');
    }

    return this.mapToDto(webhook);
  }

  /**
   * Update webhook
   */
  @Patch(':id')
  @Roles('admin', 'manager')
  @ApiOperation({ summary: 'Update webhook' })
  @ApiResponse({ status: 200, description: 'Webhook updated successfully' })
  @ApiResponse({ status: 404, description: 'Webhook not found' })
  async updateWebhook(
    @Param('id') id: string,
    @Body() dto: UpdateWebhookDto,
    @CurrentUser() user: UserPayload
  ): Promise<WebhookResponseDto> {
    const webhook = await this.webhookService.getWebhookById(id);

    if (!webhook) {
      throw new NotFoundException('Webhook not found');
    }

    // Verify webhook belongs to user's organization
    if (webhook.organizationId !== user.organizationId) {
      throw new ForbiddenException('Access denied');
    }

    const updatedWebhook = await this.webhookService.updateWebhook(id, dto);
    return this.mapToDto(updatedWebhook);
  }

  /**
   * Activate webhook
   */
  @Post(':id/activate')
  @Roles('admin', 'manager')
  @ApiOperation({ summary: 'Activate webhook' })
  @ApiResponse({ status: 200, description: 'Webhook activated successfully' })
  @ApiResponse({ status: 404, description: 'Webhook not found' })
  async activateWebhook(
    @Param('id') id: string,
    @CurrentUser() user: UserPayload
  ): Promise<{ success: boolean }> {
    const webhook = await this.webhookService.getWebhookById(id);

    if (!webhook) {
      throw new NotFoundException('Webhook not found');
    }

    // Verify webhook belongs to user's organization
    if (webhook.organizationId !== user.organizationId) {
      throw new ForbiddenException('Access denied');
    }

    await this.webhookService.activateWebhook(id);
    return { success: true };
  }

  /**
   * Deactivate webhook
   */
  @Post(':id/deactivate')
  @Roles('admin', 'manager')
  @ApiOperation({ summary: 'Deactivate webhook' })
  @ApiResponse({ status: 200, description: 'Webhook deactivated successfully' })
  @ApiResponse({ status: 404, description: 'Webhook not found' })
  async deactivateWebhook(
    @Param('id') id: string,
    @CurrentUser() user: UserPayload
  ): Promise<{ success: boolean }> {
    const webhook = await this.webhookService.getWebhookById(id);

    if (!webhook) {
      throw new NotFoundException('Webhook not found');
    }

    // Verify webhook belongs to user's organization
    if (webhook.organizationId !== user.organizationId) {
      throw new ForbiddenException('Access denied');
    }

    await this.webhookService.deactivateWebhook(id);
    return { success: true };
  }

  /**
   * Delete webhook
   */
  @Delete(':id')
  @Roles('admin', 'manager')
  @ApiOperation({ summary: 'Delete webhook' })
  @ApiResponse({ status: 200, description: 'Webhook deleted successfully' })
  @ApiResponse({ status: 404, description: 'Webhook not found' })
  async deleteWebhook(
    @Param('id') id: string,
    @CurrentUser() user: UserPayload
  ): Promise<{ success: boolean }> {
    const webhook = await this.webhookService.getWebhookById(id);

    if (!webhook) {
      throw new NotFoundException('Webhook not found');
    }

    // Verify webhook belongs to user's organization
    if (webhook.organizationId !== user.organizationId) {
      throw new ForbiddenException('Access denied');
    }

    await this.webhookService.deleteWebhook(id);
    return { success: true };
  }

  /**
   * Map webhook entity to DTO (without exposing secret)
   */
  private mapToDto(webhook: Webhook): WebhookResponseDto {
    return {
      id: webhook.id,
      url: webhook.url,
      events: webhook.events,
      status: webhook.status,
      description: webhook.description,
      headers: webhook.headers,
      retryCount: webhook.retryCount,
      lastTriggeredAt: webhook.lastTriggeredAt?.toISOString(),
      failureCount: webhook.failureCount,
      createdAt: webhook.createdAt.toISOString(),
      updatedAt: webhook.updatedAt.toISOString(),
    };
  }
}
