import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Patch,
  Post,
  Request,
  Res,
  UseGuards,
} from '@nestjs/common';
import type { Response, Request as ExpressRequest } from 'express';
import { JwtAuthGuard } from '@modules/organization/auth/guards/jwt-auth.guard';
import { SkipTransform } from '@common/decorators/skip-transform.decorator';
import { RequirePermissions } from '@common/decorators/permissions.decorator';
import { handleMeetingAttendanceError } from '../errors/handle-controller-error';
import { AgendaService } from '../services/agenda.service';
import { MeetingAccessService } from '../services/meeting-access.service';
import {
  CreateAgendaItemDto,
  CreateAgendaSectionDto,
  ReorderDto,
  UpdateAgendaItemDto,
  UpdateAgendaSectionDto,
} from '../dto/agenda.dto';
import { agendaForbiddenNotManagerOrCreator } from '../errors/agenda.error';
import { MeetingAttendanceError } from '../errors/meeting-attendance.error';

interface ReqUser {
  userId: string;
  id?: string;
  email?: string;
  permissions?: string[];
  organizationId?: string | null;
  roles?: any[];
  organizationRoles?: Record<string, string[]>;
  role?: string;
}

/**
 * 议程能力 v1.0 controller：段 / 项 CRUD + reorder + 完整议程查看。
 *
 * 端点路径：
 * - GET    /meeting-attendance/meetings/:id/agenda                    [100]
 * - POST   /meeting-attendance/meetings/:id/agenda/sections           [101]
 * - PATCH  /meeting-attendance/meetings/:id/agenda/sections/:sectionId [102]
 * - DELETE /meeting-attendance/meetings/:id/agenda/sections/:sectionId [103]
 * - PATCH  /meeting-attendance/meetings/:id/agenda/sections/reorder    [104]
 * - POST   /meeting-attendance/agenda-sections/:sectionId/items        [105]
 * - PATCH  /meeting-attendance/agenda-sections/:sectionId/items/:itemId [106]
 * - DELETE /meeting-attendance/agenda-sections/:sectionId/items/:itemId [107]
 * - PATCH  /meeting-attendance/agenda-sections/:sectionId/items/reorder [108]
 *
 * 鉴权流程：
 * 1) JwtAuthGuard 验登录
 * 2) PermissionsGuard 验 `meeting:agenda:read` / `meeting:agenda:update`（全局开关）
 * 3) controller 内 MeetingAccessService 验"会议级派生身份"（attendee / creator）
 *
 * 注：因 reorder 路径 `/agenda/sections/reorder` 比 `/agenda/sections/:sectionId` 更
 *     特化（NestJS 路径匹配按声明顺序），reorder 端点必须**先声明**于 :sectionId 之前。
 */
@Controller('meeting-attendance')
@SkipTransform()
@UseGuards(JwtAuthGuard)
export class MeetingAttendanceAgendaController {
  constructor(
    private readonly agendaService: AgendaService,
    private readonly accessService: MeetingAccessService,
  ) {}

  // ---------- GET 议程树 ----------

  @Get('meetings/:id/agenda')
  @RequirePermissions('meeting:agenda:read')
  async getAgenda(
    @Param('id') id: string,
    @Request() req: ExpressRequest,
    @Res() res: Response,
  ) {
    try {
      const actor = this.requireActor(req, res);
      if (!actor) return res;
      const ok = await this.accessService.isAttendee(id, actor);
      if (!ok) {
        return res
          .status(403)
          .json({ code: 'MEETING_ATTENDANCE_011', error: 'Not in the meeting attendee list' });
      }
      const result = await this.agendaService.getAgendaTree(id);
      return res.status(200).json(result);
    } catch (error) {
      return handleMeetingAttendanceError(res, error, 'Failed to fetch agenda', 'MeetingAttendanceAgendaController');
    }
  }

  // ---------- 段 CRUD ----------

  @Post('meetings/:id/agenda/sections')
  @RequirePermissions('meeting:agenda:update')
  async createSection(
    @Param('id') meetingId: string,
    @Body() dto: CreateAgendaSectionDto,
    @Request() req: ExpressRequest,
    @Res() res: Response,
  ) {
    try {
      const actor = this.requireActor(req, res);
      if (!actor) return res;
      if (!(await this.accessService.isManagerOrCreator(meetingId, actor))) {
        throw agendaForbiddenNotManagerOrCreator();
      }
      const result = await this.agendaService.createSection(meetingId, dto, actor, req);
      return res.status(201).json(result);
    } catch (error) {
      return handleMeetingAttendanceError(res, error, 'Failed to create agenda section', 'MeetingAttendanceAgendaController');
    }
  }

  // ⚠ reorder 必须排在 :sectionId 之前
  @Patch('meetings/:id/agenda/sections/reorder')
  @RequirePermissions('meeting:agenda:update')
  async reorderSections(
    @Param('id') meetingId: string,
    @Body() dto: ReorderDto,
    @Request() req: ExpressRequest,
    @Res() res: Response,
  ) {
    try {
      const actor = this.requireActor(req, res);
      if (!actor) return res;
      if (!(await this.accessService.isManagerOrCreator(meetingId, actor))) {
        throw agendaForbiddenNotManagerOrCreator();
      }
      const result = await this.agendaService.reorderSections(meetingId, dto.ids, actor, req);
      return res.status(200).json(result);
    } catch (error) {
      return handleMeetingAttendanceError(res, error, 'Failed to reorder sections', 'MeetingAttendanceAgendaController');
    }
  }

  @Patch('meetings/:id/agenda/sections/:sectionId')
  @RequirePermissions('meeting:agenda:update')
  async updateSection(
    @Param('id') meetingId: string,
    @Param('sectionId') sectionId: string,
    @Body() dto: UpdateAgendaSectionDto,
    @Request() req: ExpressRequest,
    @Res() res: Response,
  ) {
    try {
      const actor = this.requireActor(req, res);
      if (!actor) return res;
      if (!(await this.accessService.isManagerOrCreator(meetingId, actor))) {
        throw agendaForbiddenNotManagerOrCreator();
      }
      const result = await this.agendaService.updateSection(meetingId, sectionId, dto, actor, req);
      return res.status(200).json(result);
    } catch (error) {
      return handleMeetingAttendanceError(res, error, 'Failed to update agenda section', 'MeetingAttendanceAgendaController');
    }
  }

  @Delete('meetings/:id/agenda/sections/:sectionId')
  @RequirePermissions('meeting:agenda:update')
  async deleteSection(
    @Param('id') meetingId: string,
    @Param('sectionId') sectionId: string,
    @Request() req: ExpressRequest,
    @Res() res: Response,
  ) {
    try {
      const actor = this.requireActor(req, res);
      if (!actor) return res;
      if (!(await this.accessService.isManagerOrCreator(meetingId, actor))) {
        throw agendaForbiddenNotManagerOrCreator();
      }
      await this.agendaService.deleteSection(meetingId, sectionId, actor, req);
      return res.status(204).send();
    } catch (error) {
      return handleMeetingAttendanceError(res, error, 'Failed to delete agenda section', 'MeetingAttendanceAgendaController');
    }
  }

  // ---------- 议程项 CRUD ----------

  @Post('agenda-sections/:sectionId/items')
  @RequirePermissions('meeting:agenda:update')
  async createItem(
    @Param('sectionId') sectionId: string,
    @Body() dto: CreateAgendaItemDto,
    @Request() req: ExpressRequest,
    @Res() res: Response,
  ) {
    try {
      const actor = this.requireActor(req, res);
      if (!actor) return res;
      const meetingId = await this.resolveMeetingIdBySection(sectionId);
      if (!meetingId) {
        throw new MeetingAttendanceError(
          404,
          'Agenda section not found',
          'AGENDA_SECTION_NOT_FOUND',
        );
      }
      if (!(await this.accessService.isManagerOrCreator(meetingId, actor))) {
        throw agendaForbiddenNotManagerOrCreator();
      }
      const result = await this.agendaService.createItem(sectionId, dto, actor, req);
      return res.status(201).json(result);
    } catch (error) {
      return handleMeetingAttendanceError(res, error, 'Failed to create agenda item', 'MeetingAttendanceAgendaController');
    }
  }

  @Patch('agenda-sections/:sectionId/items/reorder')
  @RequirePermissions('meeting:agenda:update')
  async reorderItems(
    @Param('sectionId') sectionId: string,
    @Body() dto: ReorderDto,
    @Request() req: ExpressRequest,
    @Res() res: Response,
  ) {
    try {
      const actor = this.requireActor(req, res);
      if (!actor) return res;
      const meetingId = await this.resolveMeetingIdBySection(sectionId);
      if (!meetingId) {
        throw new MeetingAttendanceError(
          404,
          'Agenda section not found',
          'AGENDA_SECTION_NOT_FOUND',
        );
      }
      if (!(await this.accessService.isManagerOrCreator(meetingId, actor))) {
        throw agendaForbiddenNotManagerOrCreator();
      }
      const result = await this.agendaService.reorderItems(sectionId, dto.ids, actor, req);
      return res.status(200).json(result);
    } catch (error) {
      return handleMeetingAttendanceError(res, error, 'Failed to reorder items', 'MeetingAttendanceAgendaController');
    }
  }

  @Patch('agenda-sections/:sectionId/items/:itemId')
  @RequirePermissions('meeting:agenda:update')
  async updateItem(
    @Param('sectionId') sectionId: string,
    @Param('itemId') itemId: string,
    @Body() dto: UpdateAgendaItemDto,
    @Request() req: ExpressRequest,
    @Res() res: Response,
  ) {
    try {
      const actor = this.requireActor(req, res);
      if (!actor) return res;
      const meetingId = await this.resolveMeetingIdBySection(sectionId);
      if (!meetingId) {
        throw new MeetingAttendanceError(
          404,
          'Agenda section not found',
          'AGENDA_SECTION_NOT_FOUND',
        );
      }
      if (!(await this.accessService.isManagerOrCreator(meetingId, actor))) {
        throw agendaForbiddenNotManagerOrCreator();
      }
      const result = await this.agendaService.updateItem(sectionId, itemId, dto, actor, req);
      return res.status(200).json(result);
    } catch (error) {
      return handleMeetingAttendanceError(res, error, 'Failed to update agenda item', 'MeetingAttendanceAgendaController');
    }
  }

  @Delete('agenda-sections/:sectionId/items/:itemId')
  @RequirePermissions('meeting:agenda:update')
  async deleteItem(
    @Param('sectionId') sectionId: string,
    @Param('itemId') itemId: string,
    @Request() req: ExpressRequest,
    @Res() res: Response,
  ) {
    try {
      const actor = this.requireActor(req, res);
      if (!actor) return res;
      const meetingId = await this.resolveMeetingIdBySection(sectionId);
      if (!meetingId) {
        throw new MeetingAttendanceError(
          404,
          'Agenda section not found',
          'AGENDA_SECTION_NOT_FOUND',
        );
      }
      if (!(await this.accessService.isManagerOrCreator(meetingId, actor))) {
        throw agendaForbiddenNotManagerOrCreator();
      }
      await this.agendaService.deleteItem(sectionId, itemId, actor, req);
      return res.status(204).send();
    } catch (error) {
      return handleMeetingAttendanceError(res, error, 'Failed to delete agenda item', 'MeetingAttendanceAgendaController');
    }
  }

  // ---------- helpers ----------

  private requireActor(req: ExpressRequest, res: Response): ReqUser | null {
    const user = req.user as ReqUser | undefined;
    const userId = user?.userId ?? user?.id;
    if (!userId) {
      res.status(401).json({ error: 'Unauthorized' });
      return null;
    }
    return { ...user, userId } as ReqUser;
  }

  /** 反查 sectionId → meetingId，供 access 检查用；段不存在返回 null。 */
  private async resolveMeetingIdBySection(sectionId: string): Promise<string | null> {
    return this.agendaService.findMeetingIdBySection(sectionId);
  }
}
