import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  Param,
  Patch,
  Post,
  Req,
  UseGuards,
} from "@nestjs/common";
import { Request } from "express";
import { AuthenticatedGuard } from "../auth/authenticated.guard";
import { AbilityGuard } from "../auth/ability.guard";
import { RequireAbility } from "../auth/require-ability.decorator";
import { AuditService } from "../common/audit.service";
import { UsersService } from "./users.service";
import { CreateUserDto } from "./create-user.dto";
import { UpdateUserDto } from "./update-user.dto";
import { ResetPasswordDto } from "./reset-password.dto";

/** Every route here is ADMIN-only (ability "user:manage"). */
@UseGuards(AuthenticatedGuard, AbilityGuard)
@RequireAbility("user:manage")
@Controller("users")
export class UsersController {
  constructor(
    private readonly users: UsersService,
    private readonly audit: AuditService,
  ) {}

  private actingId(req: Request): string {
    return (req.user as { id: string }).id;
  }

  @Get()
  list() {
    return this.users.list();
  }

  @Post()
  async create(@Body() dto: CreateUserDto, @Req() req: Request) {
    const user = await this.users.create(dto);
    void this.audit.log(this.actingId(req), "user.create", {
      userId: user.id,
      email: user.email,
      role: user.role,
    });
    return user;
  }

  @Patch(":id")
  async update(
    @Param("id") id: string,
    @Body() dto: UpdateUserDto,
    @Req() req: Request,
  ) {
    const user = await this.users.update(id, dto, this.actingId(req));
    void this.audit.log(this.actingId(req), "user.update", { userId: id, changes: dto });
    return user;
  }

  @Post(":id/reset-password")
  async resetPassword(
    @Param("id") id: string,
    @Body() dto: ResetPasswordDto,
    @Req() req: Request,
  ) {
    const user = await this.users.resetPassword(id, dto.password);
    void this.audit.log(this.actingId(req), "user.reset_password", { userId: id });
    return user;
  }

  @Delete(":id")
  @HttpCode(204)
  async remove(@Param("id") id: string, @Req() req: Request) {
    const actingId = this.actingId(req);
    await this.users.remove(id, actingId);
    void this.audit.log(actingId, "user.delete", { userId: id });
  }
}
