import {
  Controller,
  Get,
  Post,
  Patch,
  Delete,
  Param,
  Body,
  Query,
  Req,
  Res,
  UseGuards,
  ParseIntPipe,
  BadRequestException,
} from '@nestjs/common';
import type { Response } from 'express';
import { JwtAuthGuard } from './../auth/guards/jwt-auth.guard';
import { ChecklistsService } from './services/checklists.service';
import { NotifyClientDto } from './dto/notify-client.dto';

// Internal, staff-facing. Same @UseGuards(JwtAuthGuard) at the controller
// level as MyAuditsController, same req.user.id extraction pattern.
@Controller()
@UseGuards(JwtAuthGuard)
export class ChecklistsController {
  constructor(private readonly service: ChecklistsService) {}

  // ── Template management (admin templates page) ──────────────────────
  /**
   * ?onlyMine=1 (or "true") scopes the list to templates created by the
   * requester. The frontend sends this whenever the logged-in user lacks
   * the "view-all" permission on the checklist-templates module, so an
   * auditor only ever sees what they personally generated.
   */
  @Get('checklist-templates')
  async listTemplates(@Query('onlyMine') onlyMine: string | undefined, @Req() req: any) {
    const userId: number = req.user.id;
    const scoped = onlyMine === '1' || onlyMine === 'true';
    return this.service.listTemplates(userId, scoped);
  }

  @Post('checklist-templates')
  async createTemplate(
    @Body() body: { name: string; is_generic: boolean; standard_id: number | null; items: { item_text: string; sort_order: number }[] },
    @Req() req: any,
  ) {
    const userId: number = req.user.id;
    return this.service.createTemplate(body, userId);
  }

  @Patch('checklist-templates/:id')
  async updateTemplate(
    @Param('id', ParseIntPipe) id: number,
    @Body() body: { name: string; is_generic: boolean; standard_id: number | null; items: { id?: number; item_text: string; sort_order: number }[] },
  ) {
    return this.service.updateTemplate(id, body);
  }

  @Delete('checklist-templates/:id')
  async deleteTemplate(@Param('id', ParseIntPipe) id: number) {
    await this.service.deleteTemplate(id);
    return { success: true };
  }

  @Get('audits/:rowId/checklist/available-templates')
  async availableTemplates(@Param('rowId', ParseIntPipe) rowId: number) {
    return this.service.getAvailableTemplates(rowId);
  }

  // ── Build → review → confirm → notify (the approved flow) ───────────

  @Post('audits/:rowId/checklist/build')
  async build(
    @Param('rowId', ParseIntPipe) rowId: number,
    @Body() body: { standard_id: number; template_item_ids: number[] },
    @Req() req: any,
  ) {
    const userId: number = req.user.id;
    return this.service.buildChecklist(rowId, body.standard_id, body.template_item_ids, userId);
  }

  /** Draft only - lets the auditor go back and change the item selection. */
  @Delete('checklists/:checklistId')
  async discardDraft(@Param('checklistId', ParseIntPipe) checklistId: number) {
    await this.service.deleteDraft(checklistId);
    return { success: true };
  }

  /** Auditor reviewed the PDF and confirmed. Client not contacted yet. */
  @Post('checklists/:checklistId/submit')
  async submit(@Param('checklistId', ParseIntPipe) checklistId: number, @Req() req: any) {
    const userId: number = req.user.id;
    return this.service.submitChecklist(checklistId, userId);
  }

  /** Explicit notify: multiple emails (auto-fetched on the frontend,
   *  editable), optional message + due date. Sends email + real-time. */
  @Post('checklists/:checklistId/notify-client')
  async notifyClient(
    @Param('checklistId', ParseIntPipe) checklistId: number,
    @Body() body: NotifyClientDto,
    @Req() req: any,
  ) {
    if (!body?.emails || !Array.isArray(body.emails) || body.emails.length === 0) {
      throw new BadRequestException('Add at least one client email.');
    }
    const userId: number = req.user.id;
    return this.service.notifyClient(checklistId, body, userId);
  }

  // ── Auditor reads ────────────────────────────────────────────────────

  /** Grouped: every checklist on the audit (one per standard) with items. */
  @Get('audits/:rowId/checklists')
  async getChecklists(@Param('rowId', ParseIntPipe) rowId: number) {
    return this.service.getChecklistsForAuditor(rowId);
  }

  /** Legacy flat list - kept for anything already calling it. */
  @Get('audits/:rowId/checklist')
  async getForAuditor(@Param('rowId', ParseIntPipe) rowId: number) {
    return this.service.getChecklistForAuditor(rowId);
  }

  // ── Review + result ─────────────────────────────────────────────────

  @Post('checklists/items/:itemId/review')
  async review(
    @Param('itemId', ParseIntPipe) itemId: number,
    @Body() body: { decision: 'approve' | 'reject'; note?: string },
    @Req() req: any,
  ) {
    if (body.decision === 'reject' && !body.note?.trim()) {
      throw new BadRequestException('A note is required when rejecting an item.');
    }
    const userId: number = req.user.id;
    return this.service.reviewItem(itemId, body.decision, body.note || null, userId);
  }

  /** ONE batched review-result notification (approved + rejected summary,
   *  or "all approved") - email + real-time on the client portal. */
  @Post('checklists/:checklistId/notify-review')
  async notifyReview(@Param('checklistId', ParseIntPipe) checklistId: number, @Req() req: any) {
    await this.service.notifyClientOfReview(checklistId, req.user?.id ?? null);
    return { success: true };
  }

  /** Legacy route name - same behavior as notify-review. */
  @Post('checklists/:checklistId/notify-rejections')
  async notifyRejections(@Param('checklistId', ParseIntPipe) checklistId: number, @Req() req: any) {
    await this.service.notifyClientOfReview(checklistId, req.user?.id ?? null);
    return { success: true };
  }

  // ── Documents ────────────────────────────────────────────────────────

  /** The checklist itself as a PDF — same file attached to the client email. */
  @Get('checklists/:checklistId/pdf')
  async checklistPdf(@Param('checklistId', ParseIntPipe) checklistId: number, @Res() res: Response) {
    const { buffer, filename } = await this.service.getChecklistPdf(checklistId);
    res.setHeader('Content-Type', 'application/pdf');
    res.setHeader('Content-Length', String(buffer.length));
    res.setHeader('Content-Disposition', `inline; filename="${encodeURIComponent(filename)}"`);
    res.end(buffer);
  }

  /** Stream an uploaded document to staff (inline view / download). */
  @Get('checklists/items/:itemId/document')
  async downloadDocument(@Param('itemId', ParseIntPipe) itemId: number, @Res() res: Response) {
    const { stream, size, mimeType, filename } = await this.service.openItemDocument(itemId);
    res.setHeader('Content-Type', mimeType);
    res.setHeader('Content-Length', String(size));
    res.setHeader('Content-Disposition', `inline; filename="${encodeURIComponent(filename)}"`);
    stream.pipe(res);
  }
}