import {
  Body,
  Controller,
  Get,
  Param,
  Patch,
  Post,
  Query,
  UseGuards,
} from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { UserRole, UserStatus } from '../common/constants/enums';
import { CurrentUser } from '../common/decorators/current-user.decorator';
import { Roles } from '../common/decorators/roles.decorator';
import { RolesGuard } from '../common/guards/roles.guard';
import { ADMIN_ROLES, MANAGEMENT_ROLES } from '../common/constants/roles';
import type { JwtUserPayload } from '../auth/jwt.types';
import { UsersService } from './users.service';
import {
  AdminCreateUserDto,
  AdminUpdateUserDto,
  UpdateSelfDto,
} from './dto/user.dto';
import {
  normalizeCreateUserInput,
  parseClientRole,
} from './user-api.mapper';

@ApiTags('users')
@ApiBearerAuth('access-token')
@Controller('users')
@UseGuards(RolesGuard)
export class UsersController {
  constructor(private readonly users: UsersService) {}

  @Get('me')
  async me(@CurrentUser() actor: JwtUserPayload) {
    const user = await this.users.requireByUid(actor.uid);
    return this.users.toClientUserWithManager(user);
  }

  @Patch('me')
  async updateMe(
    @CurrentUser() actor: JwtUserPayload,
    @Body() dto: UpdateSelfDto,
  ) {
    return this.users.updateSelf(actor.uid, dto);
  }

  @Get('reporting-managers')
  @Roles(...ADMIN_ROLES)
  async reportingManagers() {
    return this.users.listReportingManagers();
  }

  @Get()
  @Roles(...MANAGEMENT_ROLES)
  async list(
    @Query('role') role?: string,
    @Query('status') status?: UserStatus,
    @Query('search') search?: string,
    @Query('reportingManagerId') reportingManagerId?: string,
    @Query('cursor') cursor?: string,
    @Query('limit') limit?: string,
    @Query('paginated') paginated?: string,
  ) {
    const result = await this.users.list({
      role: role ? parseClientRole(role) : undefined,
      status,
      search,
      reportingManagerId,
      cursor,
      limit: limit ? Number(limit) : undefined,
    });

    if (paginated === '1' || paginated === 'true' || cursor) {
      return result;
    }

    return result.items;
  }

  @Post()
  @Roles(...ADMIN_ROLES)
  async create(@Body() dto: AdminCreateUserDto) {
    const user = await this.users.createUser(
      normalizeCreateUserInput(dto as unknown as Record<string, unknown>),
    );
    return this.users.toClientUserWithManager(user);
  }

  @Patch(':uid')
  @Roles(...ADMIN_ROLES)
  async update(@Param('uid') uid: string, @Body() dto: AdminUpdateUserDto) {
    const body = dto as unknown as Record<string, unknown>;
    return this.users.adminUpdate(uid, {
      email: body.email as string | undefined,
      fullName: (body.fullName ?? body.name) as string | undefined,
      employeeCode: body.employeeCode as string | undefined,
      mobileNumber: (body.mobileNumber ?? body.mobile) as string | undefined,
      sittingLocation: (body.sittingLocation ?? body.sitingLocation) as
        | string
        | undefined,
      role: body.role ? parseClientRole(body.role as string) : undefined,
      reportingManagerRef: (body.reportingManagerUid ?? body.reportingManagerId) as
        | string
        | undefined,
      deviceId: body.deviceId as string | undefined,
      profileImage: body.profileImage as string | undefined,
    });
  }

  @Post(':uid/deactivate')
  @Roles(...ADMIN_ROLES)
  async deactivate(@Param('uid') uid: string) {
    return this.users.deactivate(uid);
  }

  @Post(':uid/activate')
  @Roles(...ADMIN_ROLES)
  async activate(@Param('uid') uid: string) {
    return this.users.activate(uid);
  }
}
