import { Injectable } from '@nestjs/common';

// Installed with: npm i mammoth xlsx
const mammoth: any = require('mammoth');
const XLSX: any = require('xlsx');

const MAX_ITEMS = 500;
const HEADER_WORDS = /^(no\.?|s\.?\s?no\.?|sr\.?|#|sl\.?|item|items|requirement|requirements|clause|description|checklist|documents?)$/i;

@Injectable()
export class ChecklistFileParserService {
  private clean(raw: string): string {
    return raw
      .replace(/<[^>]+>/g, ' ')
      .replace(/&nbsp;/g, ' ')
      .replace(/&amp;/g, '&')
      .replace(/&lt;/g, '<')
      .replace(/&gt;/g, '>')
      .replace(/&quot;/g, '"')
      .replace(/&#39;/g, "'")
      .replace(/\s+/g, ' ')
      .trim()
      .replace(/^(\d+[.)]|[a-zA-Z][.)]|[•\-*–])\s+/, '')
      .trim();
  }

  private usable(s: string): boolean {
    return s.length >= 3 && s.length <= 500 && /[A-Za-z\u0600-\u06FF]/.test(s);
  }

  private async parseWord(buf: Buffer): Promise<string[]> {
    const { value: html } = await mammoth.convertToHtml({ buffer: buf });
    const grab = (re: RegExp) => [...html.matchAll(re)].map((m: RegExpMatchArray) => this.clean(m[1]));
    const lists = grab(/<li[^>]*>([\s\S]*?)<\/li>/gi);
    const source = lists.length ? lists : grab(/<(?:p|td)[^>]*>([\s\S]*?)<\/(?:p|td)>/gi);
    return source.filter((s) => this.usable(s));
  }

  private parseSheet(buf: Buffer): string[] {
    const wb = XLSX.read(buf, { type: 'buffer' });
    const out: string[] = [];
    for (const name of wb.SheetNames) {
      const rows: any[][] = XLSX.utils.sheet_to_json(wb.Sheets[name], { header: 1, defval: '', blankrows: false });
      rows.forEach((row, idx) => {
        const texts = row
          .filter((c) => typeof c === 'string')
          .map((c: string) => this.clean(c))
          .filter((c) => this.usable(c));
        if (!texts.length) return;
        if (idx === 0 && texts.some((t) => HEADER_WORDS.test(t))) return;
        const best = [...texts].sort((a, b) => b.length - a.length)[0];
        if (HEADER_WORDS.test(best)) return;
        out.push(best);
      });
    }
    return out;
  }

  async extract(buf: Buffer, originalName: string): Promise<{ format: string; supported: boolean; items: string[] }> {
    const ext = (originalName.split('.').pop() ?? '').toLowerCase();
    let raw: string[] = [];
    let supported = true;
    if (ext === 'docx') raw = await this.parseWord(buf);
    else if (ext === 'xlsx' || ext === 'xls') raw = this.parseSheet(buf);
    else supported = false;

    const seen = new Set<string>();
    const items: string[] = [];
    for (const r of raw) {
      const key = r.toLowerCase();
      if (seen.has(key)) continue;
      seen.add(key);
      items.push(r.slice(0, 500));
      if (items.length >= MAX_ITEMS) break;
    }
    return { format: ext, supported, items };
  }
}