import { Request, Response, NextFunction } from 'express';
import { PublicService } from '../services/PublicService';
import { AvailabilityService } from '../services/AvailabilityService';
import { BookingService } from '../services/BookingService';
import { EventTypeView } from '../views/EventTypeView';
import { SlotView } from '../views/SlotView';
import { BookingView } from '../views/BookingView';

export class PublicController {
  constructor(
    private publicService = new PublicService(),
    private availabilityService = new AvailabilityService(),
    private bookingService = new BookingService(),
  ) {}

  getHostPage = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { user, eventTypes } = await this.publicService.getHostPage(req.params.username);
      res.json(EventTypeView.toPublicHostPage(user, eventTypes));
    } catch (err) {
      next(err);
    }
  };

  getEventPage = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { user, eventType } = await this.publicService.getEventPage(
        req.params.username,
        req.params.eventSlug,
      );
      res.json(EventTypeView.toPublicPage(user, eventType));
    } catch (err) {
      next(err);
    }
  };

  getSlots = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { from, to, timezone } = req.query as { from: string; to: string; timezone: string };
      const slots = await this.availabilityService.getAvailableSlots({
        username: req.params.username,
        eventSlug: req.params.eventSlug,
        from,
        to,
        guestTimezone: timezone,
      });
      res.json(SlotView.toList(slots, timezone));
    } catch (err) {
      next(err);
    }
  };

  createBooking = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const idempotencyKey = req.headers['idempotency-key'] as string | undefined;
      const embedSource = req.headers['x-embed-key'] as string | undefined;
      const { user } = await this.publicService.getEventPage(req.params.username, req.params.eventSlug);

      const booking = await this.bookingService.createPublicBooking({
        username: req.params.username,
        eventSlug: req.params.eventSlug,
        ...req.body,
        idempotencyKey,
        embedSource,
      });

      res.status(201).json(
        BookingView.toPublicConfirmation(booking, booking.cancelUrl, user.fullName),
      );
    } catch (err) {
      next(err);
    }
  };

  cancelBooking = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const booking = await this.bookingService.cancelByGuest(req.body.token);
      res.json(BookingView.toCancelResponse(booking));
    } catch (err) {
      next(err);
    }
  };

  submitFeedback = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const booking = await this.bookingService.submitGuestFeedback(req.body);
      res.json({
        message: 'Thank you for your feedback!',
        guestRating: booking.guestRating,
      });
    } catch (err) {
      next(err);
    }
  };
}
