import { Body, Controller, Get, Inject, Param, Post, Query, UseGuards } from "@nestjs/common";
import type Redis from "ioredis";
import {
  CreateEventRequest,
  DeleteEventRequest,
  InviteEventRequest,
  ListEventsQuery,
  RsvpEventRequest,
  UpdateEventRequest,
} from "@slackwsh/contracts";
import * as messaging from "@slackwsh/messaging";
import { AuthGuard } from "../auth/auth.guard";
import { CurrentUser } from "../auth/current-user.decorator";
import type { RequestUser } from "../auth/auth.guard";
import { REDIS_PUBSUB } from "../common/redis-pubsub.provider";

@UseGuards(AuthGuard)
@Controller("workspaces/:workspaceId/events")
export class CalendarController {
  constructor(@Inject(REDIS_PUBSUB) private readonly redis: Redis) {}

  @Post()
  async create(@CurrentUser() user: RequestUser, @Param("workspaceId") workspaceId: string, @Body() body: unknown) {
    const input = CreateEventRequest.parse(body);
    return messaging.createEvent(this.redis, workspaceId, user.userId, input);
  }

  /** Windowed read — `from`/`to` are required, since recurring series are
   * expanded per request rather than materialised. */
  @Get()
  async list(@CurrentUser() user: RequestUser, @Param("workspaceId") workspaceId: string, @Query() query: unknown) {
    const filters = ListEventsQuery.parse(query);
    return { events: await messaging.listEvents(workspaceId, user.userId, filters) };
  }

  @Get(":eventId")
  async get(
    @CurrentUser() user: RequestUser,
    @Param("workspaceId") workspaceId: string,
    @Param("eventId") eventId: string,
  ) {
    return messaging.getEvent(workspaceId, user.userId, eventId);
  }

  @Post(":eventId/update")
  async update(
    @CurrentUser() user: RequestUser,
    @Param("workspaceId") workspaceId: string,
    @Param("eventId") eventId: string,
    @Body() body: unknown,
  ) {
    const input = UpdateEventRequest.parse(body);
    return messaging.updateEvent(this.redis, workspaceId, user.userId, eventId, input);
  }

  @Post(":eventId/invite")
  async invite(
    @CurrentUser() user: RequestUser,
    @Param("workspaceId") workspaceId: string,
    @Param("eventId") eventId: string,
    @Body() body: unknown,
  ) {
    const { attendeeUserIds } = InviteEventRequest.parse(body);
    return messaging.inviteToEvent(this.redis, workspaceId, user.userId, eventId, attendeeUserIds);
  }

  /** No target user in the route: you can only answer for yourself (see
   * rsvpEvent in libs/messaging/src/calendar.ts). */
  @Post(":eventId/rsvp")
  async rsvp(
    @CurrentUser() user: RequestUser,
    @Param("workspaceId") workspaceId: string,
    @Param("eventId") eventId: string,
    @Body() body: unknown,
  ) {
    const { status } = RsvpEventRequest.parse(body);
    return messaging.rsvpEvent(this.redis, workspaceId, user.userId, eventId, status);
  }

  @Post(":eventId/delete")
  async remove(
    @CurrentUser() user: RequestUser,
    @Param("workspaceId") workspaceId: string,
    @Param("eventId") eventId: string,
    @Body() body: unknown,
  ) {
    // Bodyless POST is valid here — a series delete needs no arguments, and
    // the web client omits the body entirely in that case.
    const { scope, occurrenceDate } = DeleteEventRequest.parse(body ?? {});
    await messaging.deleteEvent(this.redis, workspaceId, user.userId, eventId, { scope, occurrenceDate });
    return { deleted: true };
  }
}
