import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { Injectable, Logger } from '@nestjs/common';
import puppeteer from 'puppeteer';
import { type IPdfGeneratorService } from '../../domain/services/pdf-generator.service';

/** Vietnamese report type display names */
const REPORT_TYPE_LABELS: Record<string, string> = {
  RESIDENTIAL_MARKET: 'Thị trường nhà ở',
  INDUSTRIAL_MARKET: 'Thị trường công nghiệp',
  DISTRICT_ANALYSIS: 'Phân tích quận/huyện',
  INVESTMENT_FEASIBILITY: 'Phân tích khả thi đầu tư',
  INDUSTRIAL_LOCATION: 'Vị trí khu công nghiệp',
  PROPERTY_VALUATION: 'Định giá bất động sản',
  PORTFOLIO: 'Danh mục đầu tư',
};

interface ChartDataPoint {
  period: string;
  value: number;
  unit?: string;
}

interface ReportSection {
  title?: string;
  content?: string;
  data?: Record<string, unknown>;
  charts?: Record<string, ChartDataPoint[]>;
  projects?: Array<Record<string, unknown>>;
  summary?: Record<string, unknown>;
}

@Injectable()
export class PuppeteerPdfGeneratorService implements IPdfGeneratorService {
  private readonly logger = new Logger(PuppeteerPdfGeneratorService.name);

  async generatePdf(
    reportId: string,
    content: Record<string, unknown>,
  ): Promise<string> {
    const generatedAt = (content['generatedAt'] as string) || new Date().toISOString();
    const sections = (content['sections'] as Record<string, ReportSection>) || {};
    const reportType = (content['reportType'] as string) || '';
    const typeLabel = REPORT_TYPE_LABELS[reportType] || reportType;
    const title = (content['province'] as string)
      || (content['city'] as string)
      || (content['district'] as string)
      || reportId;

    const html = this.buildHtml(title, typeLabel, generatedAt, sections);

    const browser = await puppeteer.launch({
      headless: true,
      args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
    });

    try {
      const page = await browser.newPage();
      await page.setContent(html, { waitUntil: 'networkidle0' });

      const pdfBuffer = await page.pdf({
        format: 'A4',
        margin: { top: '2cm', right: '2cm', bottom: '2cm', left: '2cm' },
        printBackground: true,
        displayHeaderFooter: true,
        headerTemplate: '<div></div>',
        footerTemplate: `
          <div style="font-family: 'Be Vietnam Pro', Arial, sans-serif; font-size: 9px; color: #94a3b8; width: 100%; padding: 0 2cm; display: flex; justify-content: space-between;">
            <span>GoodGo AI Report</span>
            <span>Trang <span class="pageNumber"></span> / <span class="totalPages"></span></span>
          </div>
        `,
      });

      // Write to temp file
      const tmpDir = os.tmpdir();
      const filePath = path.join(tmpDir, `goodgo-report-${reportId}-${Date.now()}.pdf`);
      fs.writeFileSync(filePath, pdfBuffer);

      this.logger.log(`PDF generated: ${filePath} (${pdfBuffer.length} bytes)`);
      return filePath;
    } finally {
      await browser.close();
    }
  }

  private buildHtml(
    title: string,
    typeLabel: string,
    generatedAt: string,
    sections: Record<string, ReportSection>,
  ): string {
    const date = new Date(generatedAt);
    const formattedDate = date.toLocaleDateString('vi-VN', {
      year: 'numeric',
      month: 'long',
      day: 'numeric',
    });

    const sectionEntries = Object.entries(sections);
    const tocHtml = this.buildToc(sectionEntries);
    const sectionsHtml = sectionEntries
      .map(([key, section], index) => this.buildSection(key, section, index + 1))
      .join('\n');

    return `<!DOCTYPE html>
<html lang="vi">
<head>
  <meta charset="UTF-8">
  <style>
    @import url('https://fonts.googleapis.com/css2?family=Be+Vietnam+Pro:wght@300;400;500;600;700&display=swap');

    * { margin: 0; padding: 0; box-sizing: border-box; }

    body {
      font-family: 'Be Vietnam Pro', Arial, sans-serif;
      font-size: 11pt;
      line-height: 1.6;
      color: #1e293b;
    }

    /* ── Cover page ── */
    .cover {
      page-break-after: always;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      min-height: 85vh;
      text-align: center;
    }

    .cover-logo {
      width: 80px;
      height: 80px;
      background: linear-gradient(135deg, #10b981, #059669);
      border-radius: 20px;
      display: flex;
      align-items: center;
      justify-content: center;
      margin-bottom: 40px;
    }

    .cover-logo svg {
      width: 48px;
      height: 48px;
      fill: white;
    }

    .cover h1 {
      font-size: 28pt;
      font-weight: 700;
      color: #0f172a;
      margin-bottom: 12px;
      max-width: 600px;
    }

    .cover-type {
      font-size: 14pt;
      font-weight: 500;
      color: #059669;
      margin-bottom: 24px;
    }

    .cover-date {
      font-size: 11pt;
      color: #64748b;
      margin-bottom: 32px;
    }

    .ai-badge {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      background: linear-gradient(135deg, #f0fdf4, #ecfdf5);
      border: 1px solid #86efac;
      border-radius: 20px;
      padding: 8px 20px;
      font-size: 10pt;
      font-weight: 500;
      color: #059669;
    }

    .ai-badge svg {
      width: 16px;
      height: 16px;
      fill: #059669;
    }

    /* ── TOC ── */
    .toc {
      page-break-after: always;
    }

    .toc h2 {
      font-size: 18pt;
      font-weight: 700;
      color: #0f172a;
      margin-bottom: 24px;
      padding-bottom: 8px;
      border-bottom: 2px solid #10b981;
    }

    .toc-list {
      list-style: none;
    }

    .toc-list li {
      display: flex;
      align-items: baseline;
      padding: 8px 0;
      border-bottom: 1px dotted #cbd5e1;
    }

    .toc-num {
      font-weight: 600;
      color: #059669;
      min-width: 30px;
    }

    .toc-title {
      flex: 1;
      font-weight: 500;
    }

    /* ── Sections ── */
    .section {
      page-break-inside: avoid;
      margin-bottom: 32px;
    }

    .section-header {
      display: flex;
      align-items: center;
      gap: 12px;
      margin-bottom: 16px;
      padding-bottom: 8px;
      border-bottom: 2px solid #10b981;
    }

    .section-num {
      font-size: 14pt;
      font-weight: 700;
      color: #059669;
    }

    .section-title {
      font-size: 16pt;
      font-weight: 700;
      color: #0f172a;
    }

    .section-content {
      margin-bottom: 16px;
    }

    .section-content p {
      margin-bottom: 8px;
    }

    /* ── Charts ── */
    .chart-container {
      margin: 16px 0;
      background: #f8fafc;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      padding: 16px;
      page-break-inside: avoid;
    }

    .chart-title {
      font-size: 10pt;
      font-weight: 600;
      color: #475569;
      text-transform: uppercase;
      letter-spacing: 0.5px;
      margin-bottom: 12px;
    }

    /* ── Data tables ── */
    .data-table {
      width: 100%;
      border-collapse: collapse;
      margin: 12px 0;
      font-size: 10pt;
    }

    .data-table th {
      background: #f1f5f9;
      padding: 8px 12px;
      text-align: left;
      font-weight: 600;
      color: #334155;
      border-bottom: 2px solid #e2e8f0;
    }

    .data-table td {
      padding: 6px 12px;
      border-bottom: 1px solid #e2e8f0;
    }

    .data-table tr:nth-child(even) td {
      background: #f8fafc;
    }

    /* ── Methodology page ── */
    .methodology {
      page-break-before: always;
    }

    .methodology h2 {
      font-size: 16pt;
      font-weight: 700;
      color: #0f172a;
      margin-bottom: 16px;
      padding-bottom: 8px;
      border-bottom: 2px solid #10b981;
    }

    .methodology h3 {
      font-size: 12pt;
      font-weight: 600;
      color: #334155;
      margin: 16px 0 8px;
    }

    .methodology p, .methodology li {
      color: #475569;
      font-size: 10pt;
    }

    .methodology ul {
      margin-left: 20px;
      margin-bottom: 12px;
    }

    .methodology li {
      margin-bottom: 4px;
    }

    .contact-box {
      margin-top: 24px;
      padding: 16px;
      background: #f0fdf4;
      border: 1px solid #86efac;
      border-radius: 8px;
    }

    .disclaimer {
      margin-top: 24px;
      padding: 12px;
      background: #fffbeb;
      border: 1px solid #fcd34d;
      border-radius: 8px;
      font-size: 9pt;
      color: #92400e;
    }
  </style>
</head>
<body>

  <!-- ═══ COVER PAGE ═══ -->
  <div class="cover">
    <div class="cover-logo">
      <svg viewBox="0 0 24 24"><path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/></svg>
    </div>
    <h1>${this.escapeHtml(title)}</h1>
    <div class="cover-type">${this.escapeHtml(typeLabel)}</div>
    <div class="cover-date">${this.escapeHtml(formattedDate)}</div>
    <div class="ai-badge">
      <svg viewBox="0 0 24 24"><path d="M12 2a2 2 0 012 2c0 .74-.4 1.39-1 1.73V7h1a7 7 0 017 7h1.27c.34-.6.99-1 1.73-1a2 2 0 010 4c-.74 0-1.39-.4-1.73-1H21a7 7 0 01-7 7v1.27c.6.34 1 .99 1 1.73a2 2 0 01-4 0c0-.74.4-1.39 1-1.73V23a7 7 0 01-7-7H3.73c-.34.6-.99 1-1.73 1a2 2 0 010-4c.74 0 1.39.4 1.73 1H5a7 7 0 017-7V5.73C11.4 5.39 11 4.74 11 4a2 2 0 012-2z"/></svg>
      Powered by AI
    </div>
  </div>

  <!-- ═══ TABLE OF CONTENTS ═══ -->
  <div class="toc">
    <h2>Mục lục</h2>
    ${tocHtml}
  </div>

  <!-- ═══ EXECUTIVE SUMMARY (first section, forced to its own page) ═══ -->
  ${sectionsHtml}

  <!-- ═══ METHODOLOGY & SOURCES ═══ -->
  <div class="methodology">
    <h2>Phương pháp & Nguồn dữ liệu</h2>

    <h3>Phương pháp phân tích</h3>
    <ul>
      <li>Phân tích dữ liệu thị trường BĐS từ các sàn giao dịch lớn</li>
      <li>Mô hình định giá tự động (AVM) dựa trên machine learning</li>
      <li>Phân tích chuỗi thời gian cho dự báo xu hướng giá</li>
      <li>Xử lý ngôn ngữ tự nhiên (NLP) cho phân tích tin tức và sentiment</li>
      <li>Dữ liệu vĩ mô từ Tổng cục Thống kê và các nguồn chính thức</li>
    </ul>

    <h3>Nguồn dữ liệu</h3>
    <ul>
      <li>GoodGo Platform &mdash; dữ liệu listings và giao dịch nội bộ</li>
      <li>Tổng cục Thống kê Việt Nam (GSO)</li>
      <li>Ngân hàng Nhà nước Việt Nam (SBV)</li>
      <li>Bộ Kế hoạch và Đầu tư &mdash; dữ liệu FDI</li>
      <li>OpenStreetMap &amp; Google Maps &mdash; dữ liệu POI</li>
    </ul>

    <h3>Liên hệ</h3>
    <div class="contact-box">
      <p><strong>GoodGo AI Research</strong></p>
      <p>Email: research@goodgo.vn</p>
      <p>Website: goodgo.vn</p>
    </div>

    <div class="disclaimer">
      <strong>Miễn trừ trách nhiệm:</strong> Báo cáo này được tạo tự động bởi hệ thống AI của GoodGo và chỉ mang
      tính tham khảo. Các dữ liệu và phân tích không thay thế cho tư vấn chuyên nghiệp. GoodGo không chịu trách
      nhiệm cho bất kỳ quyết định đầu tư nào dựa trên nội dung báo cáo này.
    </div>
  </div>

</body>
</html>`;
  }

  private buildToc(entries: Array<[string, ReportSection]>): string {
    const items = entries
      .map(([, section], index) => {
        const title = section.title || 'Untitled';
        return `<li><span class="toc-num">${index + 1}.</span><span class="toc-title">${this.escapeHtml(title)}</span></li>`;
      })
      .join('\n');

    return `<ul class="toc-list">${items}</ul>`;
  }

  private buildSection(key: string, section: ReportSection, index: number): string {
    const title = section.title || key;
    const isExecutiveSummary = key === 'executive_summary';

    let html = `<div class="section" ${isExecutiveSummary ? 'style="page-break-before: always;"' : ''}>`;
    html += `<div class="section-header">`;
    html += `<span class="section-num">${index}</span>`;
    html += `<span class="section-title">${this.escapeHtml(title)}</span>`;
    html += `</div>`;

    // Text content
    if (section.content) {
      html += `<div class="section-content"><p>${this.escapeHtml(section.content)}</p></div>`;
    }

    // Charts
    if (section.charts) {
      for (const [chartKey, chartData] of Object.entries(section.charts)) {
        if (Array.isArray(chartData) && chartData.length > 0) {
          html += this.buildChart(chartKey, chartData as ChartDataPoint[]);
        }
      }
    }

    // Data tables (from macro data or similar)
    if (section.data && typeof section.data === 'object') {
      html += this.buildDataTables(section.data as Record<string, unknown>);
    }

    // Infrastructure projects table
    if (section.projects && Array.isArray(section.projects)) {
      html += this.buildProjectsTable(section.projects);
    }

    // Summary counts
    if (section.summary && typeof section.summary === 'object') {
      html += this.buildSummary(section.summary as Record<string, unknown>);
    }

    html += `</div>`;
    return html;
  }

  private buildChart(chartKey: string, data: ChartDataPoint[]): string {
    const chartLabel = chartKey
      .replace(/_/g, ' ')
      .replace(/\b\w/g, (c) => c.toUpperCase());
    const unit = data[0]?.unit || '';

    const values = data.map((d) => d.value);
    const maxVal = Math.max(...values, 1);
    const minVal = Math.min(...values, 0);
    const range = maxVal - minVal || 1;

    const width = 500;
    const height = 200;
    const paddingLeft = 60;
    const paddingRight = 20;
    const paddingTop = 20;
    const paddingBottom = 40;
    const chartWidth = width - paddingLeft - paddingRight;
    const chartHeight = height - paddingTop - paddingBottom;

    const points = data.map((d, i) => {
      const x = paddingLeft + (i / Math.max(data.length - 1, 1)) * chartWidth;
      const y = paddingTop + chartHeight - ((d.value - minVal) / range) * chartHeight;
      return { x, y, period: d.period, value: d.value };
    });

    // Build SVG line chart
    const pathD = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x.toFixed(1)} ${p.y.toFixed(1)}`).join(' ');
    const lastPoint = points[points.length - 1]!;
    const firstPoint = points[0]!;
    const areaD = pathD + ` L ${lastPoint.x.toFixed(1)} ${(paddingTop + chartHeight).toFixed(1)} L ${firstPoint.x.toFixed(1)} ${(paddingTop + chartHeight).toFixed(1)} Z`;

    // Y-axis labels (5 ticks)
    const yLabels = Array.from({ length: 5 }, (_, i) => {
      const val = minVal + (range * i) / 4;
      const y = paddingTop + chartHeight - (i / 4) * chartHeight;
      return { val, y };
    });

    // X-axis labels (show max 6)
    const step = Math.max(1, Math.ceil(data.length / 6));
    const xLabels = data
      .filter((_, i) => i % step === 0 || i === data.length - 1)
      .map((d, _idx, _arr) => {
        const originalIdx = data.indexOf(d);
        const x = paddingLeft + (originalIdx / Math.max(data.length - 1, 1)) * chartWidth;
        return { x, label: d.period };
      });

    const formatNum = (n: number): string => {
      if (Math.abs(n) >= 1_000_000_000) return (n / 1_000_000_000).toFixed(1) + 'B';
      if (Math.abs(n) >= 1_000_000) return (n / 1_000_000).toFixed(1) + 'M';
      if (Math.abs(n) >= 1_000) return (n / 1_000).toFixed(1) + 'K';
      return n.toFixed(1);
    };

    const svg = `
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}">
        <!-- Grid lines -->
        ${yLabels.map((yl) => `<line x1="${paddingLeft}" y1="${yl.y.toFixed(1)}" x2="${width - paddingRight}" y2="${yl.y.toFixed(1)}" stroke="#e2e8f0" stroke-width="1"/>`).join('\n')}

        <!-- Area fill -->
        <path d="${areaD}" fill="url(#grad-${chartKey})" opacity="0.3"/>

        <!-- Gradient -->
        <defs>
          <linearGradient id="grad-${chartKey}" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stop-color="#10b981"/>
            <stop offset="100%" stop-color="#10b981" stop-opacity="0"/>
          </linearGradient>
        </defs>

        <!-- Line -->
        <path d="${pathD}" fill="none" stroke="#10b981" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>

        <!-- Data points -->
        ${points.map((p) => `<circle cx="${p.x.toFixed(1)}" cy="${p.y.toFixed(1)}" r="3" fill="#059669" stroke="white" stroke-width="1.5"/>`).join('\n')}

        <!-- Y-axis labels -->
        ${yLabels.map((yl) => `<text x="${paddingLeft - 8}" y="${(yl.y + 4).toFixed(1)}" text-anchor="end" font-size="9" fill="#64748b" font-family="Be Vietnam Pro, Arial">${formatNum(yl.val)}</text>`).join('\n')}

        <!-- X-axis labels -->
        ${xLabels.map((xl) => `<text x="${xl.x.toFixed(1)}" y="${(paddingTop + chartHeight + 20).toFixed(1)}" text-anchor="middle" font-size="8" fill="#64748b" font-family="Be Vietnam Pro, Arial">${this.escapeHtml(xl.label)}</text>`).join('\n')}
      </svg>
    `;

    return `
      <div class="chart-container">
        <div class="chart-title">${this.escapeHtml(chartLabel)}${unit ? ` (${this.escapeHtml(unit)})` : ''}</div>
        ${svg}
      </div>
    `;
  }

  private buildDataTables(data: Record<string, unknown>): string {
    let html = '';

    for (const [key, val] of Object.entries(data)) {
      if (!Array.isArray(val) || val.length === 0) continue;

      const label = key.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
      const items = val as ChartDataPoint[];

      html += `
        <table class="data-table">
          <thead>
            <tr>
              <th colspan="3">${this.escapeHtml(label)}</th>
            </tr>
            <tr>
              <th>Kỳ</th>
              <th>Giá trị</th>
              <th>Đơn vị</th>
            </tr>
          </thead>
          <tbody>
            ${items.map((item) => `
              <tr>
                <td>${this.escapeHtml(String(item.period))}</td>
                <td>${typeof item.value === 'number' ? item.value.toLocaleString('vi-VN') : String(item.value)}</td>
                <td>${this.escapeHtml(String(item.unit || ''))}</td>
              </tr>
            `).join('')}
          </tbody>
        </table>
      `;
    }

    return html;
  }

  private buildProjectsTable(projects: Array<Record<string, unknown>>): string {
    if (projects.length === 0) return '';

    return `
      <table class="data-table">
        <thead>
          <tr>
            <th>Dự án</th>
            <th>Danh mục</th>
            <th>Trạng thái</th>
            <th>Vốn đầu tư (VND)</th>
          </tr>
        </thead>
        <tbody>
          ${projects.map((p) => `
            <tr>
              <td>${this.escapeHtml(String(p['name'] || ''))}</td>
              <td>${this.escapeHtml(String(p['category'] || ''))}</td>
              <td>${this.escapeHtml(String(p['status'] || ''))}</td>
              <td>${p['investmentVND'] ? Number(p['investmentVND']).toLocaleString('vi-VN') : '—'}</td>
            </tr>
          `).join('')}
        </tbody>
      </table>
    `;
  }

  private buildSummary(summary: Record<string, unknown>): string {
    let html = '<div class="section-content">';

    for (const [key, val] of Object.entries(summary)) {
      const label = key.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());

      if (typeof val === 'number') {
        html += `<p><strong>${this.escapeHtml(label)}:</strong> ${val.toLocaleString('vi-VN')}</p>`;
      } else if (typeof val === 'object' && val !== null) {
        html += `<p><strong>${this.escapeHtml(label)}:</strong></p>`;
        html += '<ul style="margin-left: 20px; margin-bottom: 8px;">';
        for (const [k, v] of Object.entries(val as Record<string, unknown>)) {
          html += `<li>${this.escapeHtml(k)}: ${String(v)}</li>`;
        }
        html += '</ul>';
      }
    }

    html += '</div>';
    return html;
  }

  private escapeHtml(str: string): string {
    return str
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#39;');
  }
}
