import {
  Controller,
  Get,
  Post,
  Patch,
  Delete,
  Body,
  Param,
  Query,
  Req,
  Res,
  UploadedFiles,
  UseInterceptors,
} from '@nestjs/common';
import { FilesInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import * as fs from 'fs';
import * as nodePath from 'path';
import { InquiriesService } from './inquiries.service';
import { CreateInquiryDto } from './dto/create-inquiry.dto';
import { UpdateInquiryDto } from './dto/update-inquiry.dto';
import { InquiryNotificationsService } from '../inquiry-notifications/inquiry-notifications.service';
import { Public } from '../common/guards/decorators/public.decorator';
import type { Request, Response } from 'express';

// ═════════════════════════════════════════════════════════════
// ✅ Helper: extract userId from JWT token in request
// Works whether or not you have a JwtAuthGuard active
// ═════════════════════════════════════════════════════════════
function extractUserId(req: Request): number | undefined {
  // Try 1: User attached by AuthGuard (if any)
  const fromUser =
    (req as any).user?.id ??
    (req as any).user?.sub ??
    (req as any).user?.userId;
  if (fromUser) return Number(fromUser);

  // Try 2: Decode JWT manually from Authorization header
  const auth = req.headers['authorization'] || req.headers['Authorization'];
  if (typeof auth === 'string' && auth.startsWith('Bearer ')) {
    try {
      const token = auth.slice(7);
      const parts = token.split('.');
      if (parts.length !== 3) return undefined;
      const payload = JSON.parse(
        Buffer.from(parts[1], 'base64').toString('utf-8'),
      );
      const id = payload?.sub ?? payload?.id ?? payload?.userId;
      if (id) return Number(id);
    } catch {
      /* ignore malformed token */
    }
  }

  return undefined;
}

// ═════════════════════════════════════════════════════════════
// ✅ Helper: render an Access Denied HTML page
// ═════════════════════════════════════════════════════════════
function accessDeniedHtml(): string {
  return `
    <html><body style="font-family:sans-serif;text-align:center;padding:60px;background:#f9fafb;">
      <div style="max-width:480px;margin:0 auto;background:white;padding:40px;border-radius:12px;box-shadow:0 4px 12px rgba(0,0,0,0.1);">
        <h2 style="color:#dc2626;margin:0 0 8px;">🔒 Access Denied</h2>
        <p style="color:#6b7280;margin:8px 0;">This download link is invalid or has expired.</p>
        <p style="color:#9ca3af;font-size:13px;margin-top:24px;">
          Please log in to the QRS portal or request a new email notification.
        </p>
        <a href="https://web.qrsyst.com" style="display:inline-block;margin-top:16px;padding:10px 24px;background:#0f766e;color:white;text-decoration:none;border-radius:8px;font-weight:600;">Go to Portal</a>
      </div>
    </body></html>
  `;
}

@Controller('inquiries')
export class InquiriesController {
  constructor(private readonly inquiriesService: InquiriesService) {}

  @Post()
  create(@Body() dto: CreateInquiryDto) {
    return this.inquiriesService.create(dto);
  }

  // ✅ UPDATED: passes currentUserId for row-level filtering + submitted_by_id filter
  @Get()
  findAll(
    @Req() req: Request,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
    @Query('status') status?: string,
    @Query('search') search?: string,
    @Query('submitted_by_id') submitted_by_id?: string, // ✅ NEW
  ) {
    const currentUserId = extractUserId(req);
    console.log(`[INQUIRIES-CTRL] GET /inquiries by userId=${currentUserId}`);

    return this.inquiriesService.findAll({
      page: page ? +page : 1,
      limit: limit ? +limit : 50,
      status,
      search,
      currentUserId,
      submitted_by_id, // ✅ NEW
    });
  }

  // ✅ UPDATED: pipeline summary also filters by user
  @Get('pipeline-summary')
  getPipelineSummary(@Req() req: Request) {
    const currentUserId = extractUserId(req);
    return this.inquiriesService.getPipelineSummary(currentUserId);
  }
  // ✅ NEW — Get list of all users who have submitted inquiries (for filter dropdown)
  @Get('submitters')
  getSubmitters() {
    return this.inquiriesService.getSubmittersList();
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.inquiriesService.findOne(+id);
  }

  // Scheme updates draft fields / status
  @Patch(':id')
  update(@Param('id') id: string, @Body() dto: UpdateInquiryDto) {
    return this.inquiriesService.update(+id, dto);
  }

  // Convenience endpoint: Marketing confirms the draft
  @Patch(':id/confirm')
  confirm(@Param('id') id: string) {
    return this.inquiriesService.update(+id, {
      status: 'CLIENT_CONFIRMED' as any,
    });
  }

  // Convenience endpoint: Marketing requests changes
  @Patch(':id/request-changes')
  requestChanges(@Param('id') id: string, @Body() body: { notes: string }) {
    return this.inquiriesService.update(+id, {
      status: 'CHANGES_REQUESTED' as any,
      change_request_notes: body.notes,
    });
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.inquiriesService.remove(+id);
  }

  @Patch(':id/generate-draft')
  generateDraft(@Param('id') id: string) {
    return this.inquiriesService.generateDraft(+id);
  }

  // ═════════════════════════════════════════════════════════════
  // ✅ Upload supporting documents (trade license, prev cert, etc.)
  // FormData fields: files[] + types (JSON string array, parallel)
  // ═════════════════════════════════════════════════════════════
  @Post(':id/upload-documents')
  @UseInterceptors(
    FilesInterceptor('files', 10, {
      storage: diskStorage({
        destination: (req, _file, cb) => {
          const inquiryId = req.params.id;
          const dir = nodePath.join(
            process.cwd(),
            'uploads',
            'inquiries',
            String(inquiryId),
          );
          if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
          cb(null, dir);
        },
        filename: (_req, file, cb) => {
          const ts = Date.now();
          const safe = file.originalname.replace(/[^a-zA-Z0-9._-]/g, '_');
          cb(null, `${ts}_${safe}`);
        },
      }),
      limits: { fileSize: 10 * 1024 * 1024 }, // 10MB per file
    }),
  )
  async uploadDocuments(
    @Param('id') id: string,
    @UploadedFiles() files: Express.Multer.File[],
    @Body('types') typesField: string | string[] | undefined,
    @Req() req: Request,
  ) {
    const userId = extractUserId(req);

    // Types may come as JSON string OR array of strings depending on client
    let types: string[] = [];
    if (Array.isArray(typesField)) {
      types = typesField;
    } else if (typeof typesField === 'string') {
      try {
        types = JSON.parse(typesField);
      } catch {
        types = [typesField];
      }
    }

    return this.inquiriesService.uploadDocuments(+id, files, types, userId);
  }

  // ═════════════════════════════════════════════════════════════
  // ✅ Delete a single document by index
  // ═════════════════════════════════════════════════════════════
  @Delete(':id/documents/:docIndex')
  async deleteDocument(
    @Param('id') id: string,
    @Param('docIndex') docIndex: string,
  ) {
    return this.inquiriesService.deleteDocument(+id, +docIndex);
  }

  // ═════════════════════════════════════════════════════════════
  // ✅ PUBLIC: PDF download — token-validated, no JWT required
  // ═════════════════════════════════════════════════════════════
  @Public()
  @Get(':id/download-draft/pdf')
  async downloadDraftPdf(
    @Param('id') id: string,
    @Query('token') token: string | undefined,
    @Req() req: Request,
    @Res() res: Response,
  ) {
    const inquiryId = +id;

    // Allow if: signed token valid OR authenticated user (logged in)
    const validToken =
      !!token &&
      InquiryNotificationsService.verifyDownloadToken(token, inquiryId, 'pdf');
    const validUser = !!extractUserId(req);

    if (!validToken && !validUser) {
      console.log(
        `[DOWNLOAD-PDF] DENIED inquiry=${inquiryId} hasToken=${!!token}`,
      );
      return res.status(401).send(accessDeniedHtml());
    }

    const inquiry = await this.inquiriesService.findOne(inquiryId);
    if (!inquiry?.draft_pdf_path) {
      return res.status(404).send('Draft PDF not generated yet');
    }

    const { buffer, fileName } = this.inquiriesService.getDraftFile(
      inquiry.draft_pdf_path,
    );

    res.set({
      'Content-Type': 'application/pdf',
      'Content-Disposition': `attachment; filename="${fileName}"`,
      'Content-Length': buffer.length,
      // ✅ NEW — disable browser/proxy caching so regenerated drafts are always fresh
      'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0',
      Pragma: 'no-cache',
      Expires: '0',
    });

    return res.send(buffer);
  }

  // ═════════════════════════════════════════════════════════════
  // ✅ PUBLIC: Word download — token-validated, no JWT required
  // ═════════════════════════════════════════════════════════════
  @Public()
  @Get(':id/download-draft/docx')
  async downloadDraftDocx(
    @Param('id') id: string,
    @Query('token') token: string | undefined,
    @Req() req: Request,
    @Res() res: Response,
  ) {
    const inquiryId = +id;

    const validToken =
      !!token &&
      InquiryNotificationsService.verifyDownloadToken(token, inquiryId, 'docx');
    const validUser = !!extractUserId(req);

    if (!validToken && !validUser) {
      console.log(
        `[DOWNLOAD-DOCX] DENIED inquiry=${inquiryId} hasToken=${!!token}`,
      );
      return res.status(401).send(accessDeniedHtml());
    }

    const inquiry = await this.inquiriesService.findOne(inquiryId);
    if (!inquiry?.draft_docx_path) {
      return res.status(404).send('Draft Word file not generated yet');
    }

    const { buffer, fileName } = this.inquiriesService.getDraftFile(
      inquiry.draft_docx_path,
    );

    res.set({
      'Content-Type':
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
      'Content-Disposition': `attachment; filename="${fileName}"`,
      'Content-Length': buffer.length,
      // ✅ NEW — disable browser/proxy caching
      'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0',
      Pragma: 'no-cache',
      Expires: '0',
    });

    return res.send(buffer);
  }
}