import fs from "fs";
import path from "path";
import { config } from "../config/env";

/**
 * NAS storage for offers/quotations.
 * Structure: {basePath}/{YYYY}/{prefix_seq}/{year_prefix_seq}.pdf
 * The env path (NAS_OFFERS_PATH) should point directly to the Nabídky folder.
 */

class NasOffersManager {
  private readonly basePath: string;

  constructor() {
    const raw = config.nas.offersPath;
    this.basePath = raw ? path.resolve(raw).replace(/\\/g, "/") : "";
  }

  isConfigured(): boolean {
    if (!this.basePath) return false;
    try {
      fs.mkdirSync(this.basePath, { recursive: true });
      return fs.statSync(this.basePath).isDirectory();
    } catch (err) {
      console.error(
        "[nas-offers-manager] mkdir/stat failed for basePath:",
        this.basePath,
        err,
      );
      return false;
    }
  }

  saveOfferPdf(
    quotationNumber: string,
    year: number,
    pdfBuffer: Buffer,
  ): string | null {
    const { prefix, seq } = this.parseParts(quotationNumber);
    const folderName = this.sanitizeFilename(`${prefix}_${seq}`);
    const fileName = this.sanitizeFilename(`${year}_${prefix}_${seq}`) + ".pdf";

    const dir = this.ensureDir(year, folderName);
    if (!dir) return null;

    const fullPath = path.join(dir, fileName);

    try {
      fs.writeFileSync(fullPath, pdfBuffer);
      return `${year}/${folderName}/${fileName}`;
    } catch (err) {
      console.error(
        "[nas-offers-manager] write failed for offer PDF:",
        fullPath,
        err,
      );
      return null;
    }
  }

  readOfferPdf(
    relativePath: string,
  ): { data: Buffer; fileName: string } | null {
    const fullPath = this.resolveSafePath(relativePath);
    if (!fullPath) return null;
    try {
      const data = fs.readFileSync(fullPath);
      return { data, fileName: path.basename(fullPath) };
    } catch (err) {
      console.error(
        "[nas-offers-manager] read failed for offer PDF:",
        fullPath,
        err,
      );
      return null;
    }
  }

  deleteOfferPdf(relativePath: string): boolean {
    const fullPath = this.resolveSafePath(relativePath);
    if (!fullPath) return false;
    try {
      fs.unlinkSync(fullPath);
      // Remove parent folder if empty
      const dir = path.dirname(fullPath);
      const remaining = fs.readdirSync(dir);
      if (remaining.length === 0) {
        fs.rmdirSync(dir);
      }
      return true;
    } catch (err) {
      console.error(
        "[nas-offers-manager] delete failed for offer PDF:",
        fullPath,
        err,
      );
      return false;
    }
  }

  /** Build the relative NAS path for a given quotation number + year */
  buildRelativePath(quotationNumber: string, year: number): string {
    const { prefix, seq } = this.parseParts(quotationNumber);
    const folderName = this.sanitizeFilename(`${prefix}_${seq}`);
    const fileName = this.sanitizeFilename(`${year}_${prefix}_${seq}`) + ".pdf";
    return `${year}/${folderName}/${fileName}`;
  }

  private parseParts(quotationNumber: string): {
    prefix: string;
    seq: string;
  } {
    const parts = quotationNumber.split("/");
    return {
      prefix: this.sanitizeFilename(
        parts.length >= 2 ? parts[parts.length - 2] : "NA",
      ),
      seq: this.sanitizeFilename(parts[parts.length - 1]),
    };
  }

  // ── Private helpers ──────────────────────────────────────────────

  private ensureDir(year: number, quotationNumber?: string): string | null {
    const parts = [this.basePath, String(year)];
    if (quotationNumber) parts.push(quotationNumber);
    const dirPath = path.join(...parts);
    try {
      fs.mkdirSync(dirPath, { recursive: true });
      return dirPath;
    } catch (err) {
      console.error(
        "[nas-offers-manager] mkdir failed for path:",
        dirPath,
        err,
      );
      return null;
    }
  }

  private sanitizeFilename(name: string): string {
    let safe = path.basename(name);
    safe = safe.replace(/[\x00-\x1f\x7f<>:"/\\|?*]/g, "");
    safe = safe.replace(/^[. ]+|[. ]+$/g, "");
    if ([...safe].length > 255) {
      const ext = path.extname(safe).slice(1);
      const base = path.basename(safe, ext ? "." + ext : "");
      const maxBase = 250 - [...ext].length;
      safe = ext
        ? [...base].slice(0, maxBase).join("") + "." + ext
        : [...base].slice(0, maxBase).join("");
    }
    return safe;
  }

  private resolveSafePath(relativePath: string): string | null {
    if (!this.basePath) return null;
    if (relativePath.includes("\0") || relativePath.includes("..")) {
      return null;
    }
    const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
    const candidate = path
      .resolve(this.basePath, normalized)
      .replace(/\\/g, "/");
    const normalBase = this.basePath.replace(/\\/g, "/");
    if (!candidate.startsWith(normalBase + "/")) {
      return null;
    }
    return candidate;
  }
}

export const nasOffersManager = new NasOffersManager();
