import { Controller, Get, Query, Res } from '@nestjs/common';
import type { Response } from 'express';
import {
  AgingAnalysisService,
  AgingReportOptions,
  ReportSource,
  SOURCE_MANUAL,
  SOURCE_NEW,
} from './aging-analysis.service';
import { AgingReportExcelService } from './aging-report-excel.service';
import { AgingReportPdfService } from './aging-report-pdf.service';

@Controller('reports/aging-analysis')
export class AgingAnalysisController {
  constructor(
    private readonly service: AgingAnalysisService,
    private readonly excel: AgingReportExcelService,
    private readonly pdf: AgingReportPdfService,
  ) {}

  @Get()
  json(@Query() q: Record<string, string>) {
    return this.service.generate(this.opts(q));
  }

  @Get('export/excel')
  async excelExport(@Res() res: Response, @Query() q: Record<string, string>) {
    const report = await this.service.generate(this.opts(q));
    const buf = await this.excel.build(report);
    res.setHeader(
      'Content-Type',
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    );
    res.setHeader(
      'Content-Disposition',
      'attachment; filename="aging-analysis-report.xlsx"',
    );
    res.send(buf);
  }

  @Get('export/pdf')
  async pdfExport(@Res() res: Response, @Query() q: Record<string, string>) {
    const report = await this.service.generate(this.opts(q));
    const buf = await this.pdf.build(report);
    res.setHeader('Content-Type', 'application/pdf');
    res.setHeader(
      'Content-Disposition',
      'attachment; filename="aging-analysis-report.pdf"',
    );
    res.send(buf);
  }

  private opts(q: Record<string, string>): AgingReportOptions {
    return {
      fromYear: q.fromYear ? +q.fromYear : 2023,
      toYear: q.toYear ? +q.toYear : 2026,
      fromDate: q.fromDate ? new Date(`${q.fromDate}T00:00:00`) : undefined,
      toDate: q.toDate ? new Date(`${q.toDate}T23:59:59.999`) : undefined,
      basis: this.mapBasis(q.basis),
      mode: q.mode === 'cycle' ? 'cycle' : 'range',
      year: q.year ? +q.year : undefined,
      months: this.parseMonths(q.months),
      standard: q.standard,
      category: q.category,
      source: this.mapSource(q.source),
      includeUndated: q.includeUndated === 'true',
      dedupeByCertNo: q.dedupe === 'true',
    };
  }

  /** Accepts label or aliases for the top source filter */
  private mapSource(s?: string): ReportSource | undefined {
    if (!s) return undefined; // All
    const v = s.trim().toLowerCase();
    if (['manual', 'legacy', 'previous'].includes(v)) return SOURCE_MANUAL;
    if (['new', 'qrs', 'tqs', 'qrs & tqs', 'qrs&tqs'].includes(v)) return SOURCE_NEW;
    return undefined;
  }

  /** Which date the range filters on */
  private mapBasis(s?: string): 'issue' | 'expire' | undefined {
    if (!s) return undefined; // default issue
    const v = s.trim().toLowerCase();
    if (['expire', 'expiry', 'expire_date', 'expiry_date'].includes(v)) {
      return 'expire';
    }
    return 'issue';
  }

  /** Parse "7,8" or "7-8" into [7, 8] */
  private parseMonths(s?: string): number[] | undefined {
    if (!s?.trim()) return undefined;
    const t = s.trim();
    if (t.includes('-')) {
      const [a, b] = t.split('-').map((x) => parseInt(x, 10));
      if (!isNaN(a) && !isNaN(b)) {
        const out: number[] = [];
        for (let m = a; m <= b; m++) out.push(m);
        return out;
      }
    }
    return t
      .split(',')
      .map((x) => parseInt(x.trim(), 10))
      .filter((n) => !isNaN(n) && n >= 1 && n <= 12);
  }
}
