import { Request, Response, NextFunction, Router } from 'express';
import { WebhooksService } from '../services/webhooks.service';

export class WebhooksController {
  public router: Router;

  constructor(private readonly webhooksService: WebhooksService) {
    this.router = Router();
    this.initializeRoutes();
  }

  private initializeRoutes(): void {
    // Event Types
    this.router.get('/event-types', this.findAllEventTypes.bind(this));
    this.router.get('/event-types/:code', this.findEventTypeByCode.bind(this));
    this.router.get('/event-types/category/:category', this.findEventTypesByCategory.bind(this));

    // Endpoints
    this.router.get('/endpoints', this.findAllEndpoints.bind(this));
    this.router.get('/endpoints/active', this.findActiveEndpoints.bind(this));
    this.router.get('/endpoints/:id', this.findEndpoint.bind(this));
    this.router.post('/endpoints', this.createEndpoint.bind(this));
    this.router.patch('/endpoints/:id', this.updateEndpoint.bind(this));
    this.router.delete('/endpoints/:id', this.deleteEndpoint.bind(this));
    this.router.patch('/endpoints/:id/toggle', this.toggleEndpoint.bind(this));
    this.router.get('/endpoints/:id/stats', this.getEndpointStats.bind(this));
    this.router.get('/endpoints/:id/deliveries', this.findDeliveriesForEndpoint.bind(this));

    // Events
    this.router.post('/events', this.createEvent.bind(this));
    this.router.get('/events/:id', this.findEvent.bind(this));
    this.router.get('/events/pending', this.findPendingEvents.bind(this));

    // Deliveries
    this.router.get('/deliveries/:id', this.findDelivery.bind(this));
    this.router.get('/events/:eventId/deliveries', this.findDeliveriesForEvent.bind(this));
  }

  // ============================================
  // EVENT TYPES
  // ============================================

  private async findAllEventTypes(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const eventTypes = await this.webhooksService.findAllEventTypes();
      res.json({ data: eventTypes, total: eventTypes.length });
    } catch (error) {
      next(error);
    }
  }

  private async findEventTypeByCode(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { code } = req.params;
      const eventType = await this.webhooksService.findEventTypeByCode(code);

      if (!eventType) {
        res.status(404).json({ error: 'Event type not found' });
        return;
      }

      res.json({ data: eventType });
    } catch (error) {
      next(error);
    }
  }

  private async findEventTypesByCategory(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { category } = req.params;
      const eventTypes = await this.webhooksService.findEventTypesByCategory(category);
      res.json({ data: eventTypes, total: eventTypes.length });
    } catch (error) {
      next(error);
    }
  }

  // ============================================
  // ENDPOINTS
  // ============================================

  private async findAllEndpoints(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const endpoints = await this.webhooksService.findAllEndpoints(tenantId);
      res.json({ data: endpoints, total: endpoints.length });
    } catch (error) {
      next(error);
    }
  }

  private async findActiveEndpoints(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const endpoints = await this.webhooksService.findActiveEndpoints(tenantId);
      res.json({ data: endpoints, total: endpoints.length });
    } catch (error) {
      next(error);
    }
  }

  private async findEndpoint(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const endpoint = await this.webhooksService.findEndpoint(id);

      if (!endpoint) {
        res.status(404).json({ error: 'Endpoint not found' });
        return;
      }

      res.json({ data: endpoint });
    } catch (error) {
      next(error);
    }
  }

  private async createEndpoint(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = req.headers['x-user-id'] as string;

      const endpoint = await this.webhooksService.createEndpoint(tenantId, req.body, userId);
      res.status(201).json({ data: endpoint });
    } catch (error) {
      next(error);
    }
  }

  private async updateEndpoint(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const userId = req.headers['x-user-id'] as string;

      const endpoint = await this.webhooksService.updateEndpoint(id, req.body, userId);

      if (!endpoint) {
        res.status(404).json({ error: 'Endpoint not found' });
        return;
      }

      res.json({ data: endpoint });
    } catch (error) {
      next(error);
    }
  }

  private async deleteEndpoint(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const deleted = await this.webhooksService.deleteEndpoint(id);

      if (!deleted) {
        res.status(404).json({ error: 'Endpoint not found' });
        return;
      }

      res.status(204).send();
    } catch (error) {
      next(error);
    }
  }

  private async toggleEndpoint(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const { isActive } = req.body;

      const endpoint = await this.webhooksService.toggleEndpoint(id, isActive);

      if (!endpoint) {
        res.status(404).json({ error: 'Endpoint not found' });
        return;
      }

      res.json({ data: endpoint });
    } catch (error) {
      next(error);
    }
  }

  private async getEndpointStats(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const startDate = new Date(req.query.startDate as string || Date.now() - 7 * 24 * 60 * 60 * 1000);
      const endDate = new Date(req.query.endDate as string || Date.now());

      const stats = await this.webhooksService.getEndpointStats(id, startDate, endDate);
      res.json({ data: stats });
    } catch (error) {
      next(error);
    }
  }

  private async findDeliveriesForEndpoint(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const limit = parseInt(req.query.limit as string) || 50;

      const deliveries = await this.webhooksService.findDeliveriesForEndpoint(id, limit);
      res.json({ data: deliveries, total: deliveries.length });
    } catch (error) {
      next(error);
    }
  }

  // ============================================
  // EVENTS
  // ============================================

  private async createEvent(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const event = await this.webhooksService.createEvent(tenantId, req.body);
      res.status(201).json({ data: event });
    } catch (error) {
      next(error);
    }
  }

  private async findEvent(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const event = await this.webhooksService.findEvent(id);

      if (!event) {
        res.status(404).json({ error: 'Event not found' });
        return;
      }

      res.json({ data: event });
    } catch (error) {
      next(error);
    }
  }

  private async findPendingEvents(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const limit = parseInt(req.query.limit as string) || 100;
      const events = await this.webhooksService.findPendingEvents(limit);
      res.json({ data: events, total: events.length });
    } catch (error) {
      next(error);
    }
  }

  // ============================================
  // DELIVERIES
  // ============================================

  private async findDelivery(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const delivery = await this.webhooksService.findDelivery(id);

      if (!delivery) {
        res.status(404).json({ error: 'Delivery not found' });
        return;
      }

      res.json({ data: delivery });
    } catch (error) {
      next(error);
    }
  }

  private async findDeliveriesForEvent(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { eventId } = req.params;
      const deliveries = await this.webhooksService.findDeliveriesForEvent(eventId);
      res.json({ data: deliveries, total: deliveries.length });
    } catch (error) {
      next(error);
    }
  }
}
