/**
 * ════════════════════════════════════════════════════════════════════
 * audit-report.controller.ts
 * ────────────────────────────────────────────────────────────────────
 * THIN controller — every method just delegates to a service.
 * Routes are mounted under /api/audit-report.
 *
 * NOTE: keep the more specific routes ABOVE any ":param" routes, same
 * rule that bit you on the previous-nc controller. There are no greedy
 * param routes here, but keep the habit.
 * ════════════════════════════════════════════════════════════════════
 */
import {
  Controller,
  Get,
  Query,
  Param,
  Res,
  StreamableFile,
  BadRequestException,
  ParseIntPipe,
  Logger,
  Body,
  Post,
  Req,
  ForbiddenException,   // 🆕                        // 🆕 add Req
} from '@nestjs/common';
import type { Response } from 'express';   // 🆕 THIS LINE fixes the res.set errors

import { AuditAssignReportService } from '../services/audit-assign-report.service';
import { AuditDetailReportService } from '../services/audit-detail-report.service';
import type { AuditDetailFilters } from '../services/audit-detail-report.service';
import { AuditReportFileService } from '../services/audit-report-file.service';
import { AuditReportExcelService } from '../services/audit-report-excel.service';
import { AuditReportPdfService } from '../services/audit-report-pdf.service';
import { AuditTable, AUDIT_TABLES } from '../shared/audit-query.helper';
import { AuditAssistantService } from '../services/audit-assistant.service';
import { PreviousNcService } from '../../previous-nc/services/previous-nc.service';  // fix path to yours

@Controller('audit-report')
export class AuditReportController {
  private readonly logger = new Logger('AuditReportController');

  constructor(
    private readonly assignReport: AuditAssignReportService,
    private readonly detailReport: AuditDetailReportService,
    private readonly fileService: AuditReportFileService,
    private readonly excelService: AuditReportExcelService,
    private readonly pdfService: AuditReportPdfService,
    private readonly assistant: AuditAssistantService,   // 🆕 add this
    private readonly previousNc: PreviousNcService,   // 🆕

  ) { }

  // GET /api/audit-report/assign  → aggregated per-auditor report
  @Get('assign')
  getAssign() {
    return this.assignReport.build();
  }

  // GET /api/audit-report/detail?source=QRS&audit_type=Initial&year=2026&month=04&page=1&limit=50
  @Get('detail')
  async getDetail(@Query() q: AuditDetailFilters, @Req() req: any) {
    const currentUserId = req.user?.id;
    const canViewAll = await this.previousNc.userCanViewAll(currentUserId);

    const role = (req.user?.role || '').toLowerCase();        // 🆕 adjust to your user shape
    const seesAll = canViewAll || role === 'auditor';         // 🆕 auditors also see all

    const scoped = seesAll ? q : { ...q, viewerUserId: currentUserId, auditor: undefined };
    const result = await this.detailReport.build(scoped);
    return { ...result, can_manage: canViewAll };
  }
  // POST /api/audit-report/transfer — reassign an audit (admins only)
  @Post('transfer')
  async transferAudit(
    @Body() body: {
      source: 'QRS' | 'TQS' | 'QRS & TQS';
      table?: string;
      record_id: number;
      from_auditor_id: number;
      to_user_id: number;
    },
    @Req() req: any,
  ) {
    const canViewAll = await this.previousNc.userCanViewAll(req.user?.id);
    if (!canViewAll) throw new ForbiddenException('Not allowed to transfer audits');
    return this.detailReport.transferAudit(body);
  }
  // GET /api/audit-report/auditors — list of users audits can be transferred to (admins only)
  @Get('auditors')
  async listAuditors(@Req() req: any) {
    const canViewAll = await this.previousNc.userCanViewAll(req.user?.id);
    if (!canViewAll) throw new ForbiddenException('Not allowed');
    return this.detailReport.listAuditors();
  }
  @Post('assistant')
  async askAssistant(
    @Body() body: { message: string; history?: { role: 'user' | 'assistant'; content: string }[] },
    @Req() req: any,             // 🆕 grab the authenticated request
  ) {
    const currentUserId = req.user?.id;   // 🆕
    const canViewAll = await this.previousNc.userCanViewAll(currentUserId);   // 🆕
    return this.assistant.ask(body.message, body.history ?? [], {   // 🆕 third arg
      currentUserId,
      canViewAll,
    });
  }
  // GET /api/audit-report/export/excel?<same filters as /detail>
  @Get('export/excel')
  async exportExcel(@Query() q: AuditDetailFilters, @Res({ passthrough: true }) res: Response): Promise<StreamableFile> {
    const data = await this.detailReport.build({ ...q, page: 1, limit: 100000 });
    const buf = await this.excelService.generateAuditReportExcel(data, this.filterSubtitle(q));
    const name = `audit-report-${new Date().toISOString().slice(0, 10)}.xlsx`;
    res.set({
      'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      'Content-Disposition': `attachment; filename="${name}"`,
      'Content-Length': buf.length.toString(),
    });
    return new StreamableFile(buf);
  }

  // GET /api/audit-report/export/pdf?<same filters as /detail>
  @Get('export/pdf')
  async exportPdf(@Query() q: AuditDetailFilters, @Res({ passthrough: true }) res: Response): Promise<StreamableFile> {
    const data = await this.detailReport.build({ ...q, page: 1, limit: 100000 });
    const buf = await this.pdfService.generateAuditReportPdf(data, this.filterSubtitle(q));
    const name = `audit-report-${new Date().toISOString().slice(0, 10)}.pdf`;
    res.set({
      'Content-Type': 'application/pdf',
      'Content-Disposition': `attachment; filename="${name}"`,
      'Content-Length': buf.length.toString(),
    });
    return new StreamableFile(buf);
  }

  /** Build a human subtitle from the active filters for the report header. */
  private filterSubtitle(q: AuditDetailFilters): string {
    const parts: string[] = [];
    if (q.source) parts.push(`Source: ${q.source}`);
    if (q.auditor) parts.push(`Auditor: ${q.auditor}`);
    if (q.audit_type) parts.push(`Type: ${q.audit_type}`);
    if (q.year) parts.push(`Year: ${q.year}`);
    if (q.month) parts.push(`Month: ${q.month}`);
    if (q.phase) parts.push(`Phase: ${q.phase}`);
    if (q.report_status) parts.push(`Report: ${q.report_status}`);
    if (q.search) parts.push(`Search: "${q.search}"`);
    return parts.length ? parts.join('  |  ') : 'All audits (no filter)';
  }

  // GET /api/audit-report/file/url?source=QRS&table=clients__clientdatas&id=123&stage=2
  // Returns a public URL the frontend can open in a new tab (Strategy A).
  @Get('file/url')
  async getFileUrl(
    @Query('source') source: string,
    @Query('table') table: string,
    @Query('id', ParseIntPipe) id: number,
    @Query('stage', ParseIntPipe) stage: number,
  ) {
    const src = this.validSource(source);
    const tbl = this.validTable(table);
    const st = this.validStage(stage);
    return this.fileService.getPublicUrl(src, tbl, id, st);
  }

  // GET /api/audit-report/file/stream?source=QRS&table=...&id=123&stage=2
  // Streams the actual file bytes from disk (Strategy B).
  @Get('file/stream')
  async streamFile(
    @Query('source') source: string,
    @Query('table') table: string,
    @Query('id', ParseIntPipe) id: number,
    @Query('stage', ParseIntPipe) stage: number,
    @Res({ passthrough: true }) res: Response,
  ): Promise<StreamableFile> {
    const src = this.validSource(source);
    const tbl = this.validTable(table);
    const st = this.validStage(stage);

    const { stream, size, mimeType, filename } =
      await this.fileService.openFile(src, tbl, id, st);

    res.set({
      'Content-Type': mimeType,
      'Content-Length': size.toString(),
      'Content-Disposition': `inline; filename="${encodeURIComponent(filename)}"`,
      'Cache-Control': 'private, max-age=300',
    });
    return new StreamableFile(stream);
  }

  // ── validators ──
  private validSource(s: string): 'QRS' | 'TQS' {
    const up = (s || '').toUpperCase();
    if (up !== 'QRS' && up !== 'TQS') {
      throw new BadRequestException(`source must be QRS or TQS`);
    }
    return up as 'QRS' | 'TQS';
  }
  private validTable(t: string): AuditTable {
    if (!AUDIT_TABLES.includes(t as AuditTable)) {
      throw new BadRequestException(`table must be one of ${AUDIT_TABLES.join(', ')}`);
    }
    return t as AuditTable;
  }
  private validStage(n: number): 1 | 2 {
    if (n !== 1 && n !== 2) throw new BadRequestException(`stage must be 1 or 2`);
    return n as 1 | 2;
  }
}