import fs from 'fs';
import path from 'path';

/**
 * Adobe PDF Services integration — the Autotag PDF API (cloud) generates a
 * tagged, accessible PDF. Used when REMEDIATION_ENGINE=adobe.
 *
 * Credentials resolve in this order:
 *   1. ADOBE_CLIENT_ID + ADOBE_CLIENT_SECRET env vars
 *   2. The JSON downloaded from the Adobe Developer Console
 *      (ADOBE_CREDENTIALS_PATH, default: ../adobe-sdk/pdfservices-api-credentials.json)
 *
 * Note: this is a cloud API — documents are uploaded to Adobe, and usage
 * counts against the account's Document Transactions quota.
 */

export interface AdobeStatus {
  enabled: boolean;
  credentialSource: 'env' | 'file' | 'none';
  reason?: string;
}

interface AdobeCreds {
  clientId: string;
  clientSecret: string;
}

function credentialsFilePath(): string {
  // One level up from src/ is the repo root. This needed two levels when the
  // API lived in a backend/ subfolder; it now resolves outside the repo.
  return process.env.ADOBE_CREDENTIALS_PATH ||
    path.join(__dirname, '..', 'adobe-sdk', 'pdfservices-api-credentials.json');
}

function loadCreds(): { creds: AdobeCreds | null; source: AdobeStatus['credentialSource'] } {
  if (process.env.ADOBE_CLIENT_ID && process.env.ADOBE_CLIENT_SECRET) {
    return { creds: { clientId: process.env.ADOBE_CLIENT_ID, clientSecret: process.env.ADOBE_CLIENT_SECRET }, source: 'env' };
  }
  try {
    const file = credentialsFilePath();
    if (fs.existsSync(file)) {
      const json = JSON.parse(fs.readFileSync(file, 'utf-8'));
      const cc = json?.client_credentials;
      if (cc?.client_id && cc?.client_secret) {
        return { creds: { clientId: cc.client_id, clientSecret: cc.client_secret }, source: 'file' };
      }
    }
  } catch { /* fall through */ }
  return { creds: null, source: 'none' };
}

export function getAdobeStatus(): AdobeStatus {
  const { creds, source } = loadCreds();
  if (!creds) {
    return {
      enabled: false, credentialSource: 'none',
      reason: 'No Adobe credentials — set ADOBE_CLIENT_ID/ADOBE_CLIENT_SECRET or provide pdfservices-api-credentials.json.',
    };
  }
  return { enabled: true, credentialSource: source };
}

export interface AdobeAutotagResult {
  ok: boolean;
  error?: string;
}

/**
 * Run Adobe Autotag on a PDF: upload → tag → download the tagged PDF.
 * Resolves with ok:false (never throws) so callers can fall back cleanly.
 */
export async function adobeAutotag(inputPath: string, outputPath: string): Promise<AdobeAutotagResult> {
  const { creds } = loadCreds();
  if (!creds) return { ok: false, error: getAdobeStatus().reason };

  let readStream: fs.ReadStream | undefined;
  try {
    // Lazy require keeps startup fast and avoids the SDK's log4js init unless used.
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    const {
      ServicePrincipalCredentials, PDFServices, MimeType, AutotagPDFJob, AutotagPDFResult,
    } = require('@adobe/pdfservices-node-sdk');

    const credentials = new ServicePrincipalCredentials({
      clientId: creds.clientId,
      clientSecret: creds.clientSecret,
    });
    const pdfServices = new PDFServices({ credentials });

    readStream = fs.createReadStream(path.resolve(inputPath));
    const inputAsset = await pdfServices.upload({ readStream, mimeType: MimeType.PDF });

    const job = new AutotagPDFJob({ inputAsset });
    const pollingURL = await pdfServices.submit({ job });
    const response = await pdfServices.getJobResult({ pollingURL, resultType: AutotagPDFResult });

    const resultAsset = response.result.taggedPDF;
    const streamAsset = await pdfServices.getContent({ asset: resultAsset });

    const out = path.resolve(outputPath);
    await new Promise<void>((resolve, reject) => {
      const ws = fs.createWriteStream(out);
      streamAsset.readStream.pipe(ws);
      ws.on('finish', resolve);
      ws.on('error', reject);
    });

    if (!fs.existsSync(out) || fs.statSync(out).size === 0) {
      return { ok: false, error: 'Adobe Autotag produced no output file.' };
    }
    return { ok: true };
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    return { ok: false, error: `Adobe Autotag failed: ${message}` };
  } finally {
    readStream?.destroy();
  }
}
