import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Body,
  Param,
  Query,
  UseGuards,
  Request,
  BadRequestException,
} from '@nestjs/common';
import { RbacService } from './rbac.service';
import {
  CreateRoleDto,
  UpdateRoleDto,
  CreateUserDto,
  UpdateUserDto,
  ResetPasswordDto,
  UpdateProfileDto,
} from './dto/rbac.dto';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RequirePermission } from '../auth/decorators/permission.decorator';
import { OperationLogsService } from '../operation-logs/operation-logs.service';
import { extractRequestInfo } from '../common/request-utils';

@UseGuards(JwtAuthGuard)
@Controller('rbac')
export class RbacController {
  constructor(
    private rbacService: RbacService,
    private logService: OperationLogsService,
  ) {}

  // ==================== 角色管理 ====================

  @Get('roles')
  @RequirePermission('role:view')
  findAllRoles() {
    return this.rbacService.findAllRoles();
  }

  @Get('roles/:id')
  @RequirePermission('role:view')
  findRoleById(@Param('id') id: string) {
    return this.rbacService.findRoleById(+id);
  }

  @Post('roles')
  @RequirePermission('role:create')
  async createRole(@Body() dto: CreateRoleDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.rbacService.createRole(dto);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: 'RBAC',
      action: '创建角色',
      detail: `角色: ${dto.name}`,
      ipAddress,
      userAgent,
    });
    return result;
  }

  @Put('roles/:id')
  @RequirePermission('role:edit')
  async updateRole(@Param('id') id: string, @Body() dto: UpdateRoleDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    try {
      const result = await this.rbacService.updateRole(+id, dto);
      await this.logService.log({
        userId: req.user?.id,
        username: req.user?.username,
        module: 'RBAC',
        action: '编辑角色',
        targetId: +id,
        targetType: 'role',
        detail: JSON.stringify(dto),
        ipAddress,
        userAgent,
      });
      return result;
    } catch (e: any) {
      throw new BadRequestException(e.message);
    }
  }

  @Delete('roles/:id')
  @RequirePermission('role:delete')
  async deleteRole(@Param('id') id: string, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    try {
      const result = await this.rbacService.deleteRole(+id);
      await this.logService.log({
        userId: req.user?.id,
        username: req.user?.username,
        module: 'RBAC',
        action: '停用角色',
        targetId: +id,
        targetType: 'role',
        ipAddress,
        userAgent,
      });
      return result;
    } catch (e: any) {
      throw new BadRequestException(e.message);
    }
  }

  // ==================== 权限管理 ====================

  @Get('permissions')
  @RequirePermission('role:view')
  findAllPermissions() {
    return this.rbacService.findAllPermissions();
  }

  @Get('permissions/tree')
  @RequirePermission('role:view')
  getPermissionTree() {
    return this.rbacService.getPermissionTree();
  }

  // ==================== 用户管理 ====================

  @Get('users')
  @RequirePermission('user:view', 'teacher:view')
  getUsers(@Query('isArchived') isArchived?: string) {
    const archived = isArchived === 'true';
    return this.rbacService.findAllUsers(archived);
  }

  @Post('users')
  @RequirePermission('user:create')
  async createUser(@Body() dto: CreateUserDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    try {
      const result = await this.rbacService.createUser(dto);
      await this.logService.log({
        userId: req.user?.id,
        username: req.user?.username,
        module: '账号',
        action: '创建账号',
        detail: `用户名: ${dto.username}`,
        ipAddress,
        userAgent,
      });
      return result;
    } catch (e: any) {
      throw new BadRequestException(e.message);
    }
  }

  @Put('users/:id')
  @RequirePermission('user:edit')
  async updateUser(@Param('id') id: string, @Body() dto: UpdateUserDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    try {
      const result = await this.rbacService.updateUser(+id, dto);
      await this.logService.log({
        userId: req.user?.id,
        username: req.user?.username,
        module: '账号',
        action: '更新账号',
        targetId: +id,
        targetType: 'user',
        detail: JSON.stringify(dto),
        ipAddress,
        userAgent,
      });
      return result;
    } catch (e: any) {
      throw new BadRequestException(e.message);
    }
  }

  @Put('users/:id/password')
  @RequirePermission('user:reset-password')
  async resetPassword(@Param('id') id: string, @Body() dto: ResetPasswordDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    try {
      const result = await this.rbacService.resetPassword(+id, dto.password);
      await this.logService.log({
        userId: req.user?.id,
        username: req.user?.username,
        module: '账号',
        action: '重置密码',
        targetId: +id,
        targetType: 'user',
        ipAddress,
        userAgent,
      });
      return result;
    } catch (e: any) {
      throw new BadRequestException(e.message);
    }
  }

  @Put('users/:id/archive')
  @RequirePermission('user:edit')
  async archiveUser(@Param('id') id: string) {
    try {
      return await this.rbacService.archiveUser(+id);
    } catch (e: unknown) {
      const err = e as { message?: string };
      throw new BadRequestException(err?.message);
    }
  }

  @Put('users/:id/restore')
  @RequirePermission('user:edit')
  async restoreUser(@Param('id') id: string) {
    try {
      return await this.rbacService.restoreUser(+id);
    } catch (e: unknown) {
      const err = e as { message?: string };
      throw new BadRequestException(err?.message);
    }
  }

  @Put('users/:id/mark-staff')
  @RequirePermission('user:edit')
  async markAsStaff(@Param('id') id: string) {
    try {
      return await this.rbacService.markAsStaff(+id);
    } catch (e: unknown) {
      const err = e as { message?: string };
      throw new BadRequestException(err?.message);
    }
  }

  @Put('users/:id/mark-student')
  @RequirePermission('user:edit')
  async markAsStudent(@Param('id') id: string) {
    try {
      return await this.rbacService.markAsStudent(+id);
    } catch (e: unknown) {
      const err = e as { message?: string };
      throw new BadRequestException(err?.message);
    }
  }

  // ---- 用户资料 ----

  @Get('users/:id/profile')
  @RequirePermission('user:view')
  getUserProfile(@Param('id') id: string) {
    return this.rbacService.getUserProfile(+id);
  }

  @Put('users/:id/profile')
  @RequirePermission('user:edit')
  async updateUserProfile(
    @Param('id') id: string,
    @Body() dto: UpdateProfileDto,
    @Request() req: any,
  ) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    try {
      const result = await this.rbacService.updateUserProfile(+id, dto);
      await this.logService.log({
        userId: req.user?.id,
        username: req.user?.username,
        module: '账号',
        action: '更新资料',
        targetId: +id,
        targetType: 'user',
        ipAddress,
        userAgent,
      });
      return result;
    } catch (e: any) {
      throw new BadRequestException(e.message);
    }
  }

  // ---- 教师工作台 ----

  @Get('teacher-workspace')
  @RequirePermission('teacher-workspace:view')
  async getTeacherWorkspace(@Request() req: any) {
    return this.rbacService.getTeacherWorkspace(req.user?.id);
  }

  // ---- 教师管理 ----

  @Get('teachers')
  @RequirePermission('teacher:view')
  async getTeachers(
    @Query('search') search?: string,
    @Query('page') page?: string,
    @Query('pageSize') pageSize?: string,
  ) {
    return this.rbacService.getTeachers({
      search,
      page: page ? +page : undefined,
      pageSize: pageSize ? +pageSize : undefined,
    });
  }

  @Put('teachers/:id/profile')
  @RequirePermission('teacher:edit')
  async updateTeacherProfile(
    @Param('id') id: string,
    @Body() profile: UpdateProfileDto,
    @Request() req: { user?: { id: number; username: string } },
  ) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.rbacService.updateTeacherProfile(+id, profile);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '教师管理',
      action: '编辑档案',
      targetId: +id,
      targetType: 'user',
      detail: '更新教师档案',
      ipAddress,
      userAgent,
    });
    return result;
  }
}
