const fs = require('fs');
const logger = require('./logger').child('AUDNEX');

const AUDNEX_BASE_URL = 'https://api.audnex.us';
const AUDNEX_TIMEOUT_MS = 10000;
const ASIN_PATTERN = /B0[0-9A-Z]{8}/u;

function normalizeAsin(value) {
  const raw = String(value || '').trim().toUpperCase();
  return ASIN_PATTERN.test(raw) ? raw : null;
}

async function extractAsinFromAaxFile(filePath) {
  const sourcePath = String(filePath || '').trim();
  if (!sourcePath) {
    return null;
  }

  return new Promise((resolve, reject) => {
    let printableWindow = '';
    let settled = false;
    const stream = fs.createReadStream(sourcePath, { highWaterMark: 64 * 1024 });

    const finish = (value) => {
      if (settled) {
        return;
      }
      settled = true;
      resolve(value);
    };

    stream.on('data', (chunk) => {
      if (settled) {
        return;
      }

      for (const byte of chunk) {
        if (byte >= 32 && byte <= 126) {
          printableWindow = `${printableWindow}${String.fromCharCode(byte)}`.slice(-48);
          const match = printableWindow.match(/B0[0-9A-Z]{8}/u);
          if (match?.[0]) {
            const asin = normalizeAsin(match[0]);
            if (asin) {
              logger.info('asin:detected', { filePath: sourcePath, asin });
              stream.destroy();
              finish(asin);
              return;
            }
          }
        } else {
          printableWindow = '';
        }
      }
    });

    stream.on('error', (error) => {
      if (settled) {
        return;
      }
      settled = true;
      reject(error);
    });

    stream.on('close', () => {
      if (!settled) {
        finish(null);
      }
    });
  });
}

async function audnexFetch(url) {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), AUDNEX_TIMEOUT_MS);
  try {
    const response = await fetch(url, {
      headers: {
        'Accept': 'application/json',
        'User-Agent': 'Ripster/1.0'
      },
      signal: controller.signal
    });
    clearTimeout(timer);
    if (!response.ok) {
      throw new Error(`Audnex Anfrage fehlgeschlagen (${response.status})`);
    }
    return response.json();
  } catch (error) {
    clearTimeout(timer);
    throw error;
  }
}

function extractChapterArray(payload) {
  if (Array.isArray(payload)) {
    return payload;
  }
  const candidates = [
    payload?.chapters,
    payload?.data?.chapters,
    payload?.content?.chapters,
    payload?.results?.chapters
  ];
  return candidates.find((entry) => Array.isArray(entry)) || [];
}

function normalizeAudnexChapter(entry, index) {
  const startOffsetMs = Number(
    entry?.startOffsetMs
    ?? entry?.startMs
    ?? entry?.offsetMs
    ?? 0
  );
  const lengthMs = Number(
    entry?.lengthMs
    ?? entry?.durationMs
    ?? entry?.length
    ?? 0
  );
  const title = String(entry?.title || entry?.chapterTitle || `Kapitel ${index + 1}`).trim() || `Kapitel ${index + 1}`;
  const safeStartMs = Number.isFinite(startOffsetMs) && startOffsetMs >= 0 ? Math.round(startOffsetMs) : 0;
  const safeLengthMs = Number.isFinite(lengthMs) && lengthMs > 0 ? Math.round(lengthMs) : 0;

  return {
    index: index + 1,
    title,
    startMs: safeStartMs,
    endMs: safeStartMs + safeLengthMs,
    startSeconds: Math.round(safeStartMs / 1000),
    endSeconds: Math.round((safeStartMs + safeLengthMs) / 1000)
  };
}

function normalizeNameList(items) {
  if (!Array.isArray(items) || items.length === 0) {
    return null;
  }
  const names = items
    .map((item) => String(item?.name || '').trim())
    .filter(Boolean);
  return names.length > 0 ? names.join(', ') : null;
}

async function fetchBookByAsin(asin, region = 'de') {
  const normalizedAsin = normalizeAsin(asin);
  if (!normalizedAsin) {
    return null;
  }

  const url = new URL(`${AUDNEX_BASE_URL}/books/${normalizedAsin}`);
  url.searchParams.set('region', String(region || 'de').trim() || 'de');
  logger.info('book:fetch:start', { asin: normalizedAsin, url: url.toString() });

  const payload = await audnexFetch(url.toString());
  if (!payload || typeof payload !== 'object') {
    return null;
  }

  const narrator = normalizeNameList(payload.narrators);
  const author = normalizeNameList(payload.authors);
  const title = String(payload.title || '').trim() || null;
  const series = String(payload.seriesName || payload.series || '').trim() || null;
  const part = String(payload.seriesPart || payload.part || '').trim() || null;
  const description = String(payload.summary || payload.description || '').trim() || null;
  const year = payload.releaseDate
    ? String(payload.releaseDate).slice(0, 4)
    : null;

  logger.info('book:fetch:done', { asin: normalizedAsin, narrator, author, title });
  return { narrator, author, title, series, part, description, year };
}

async function fetchChaptersByAsin(asin, region = 'de') {
  const normalizedAsin = normalizeAsin(asin);
  if (!normalizedAsin) {
    return [];
  }

  const url = new URL(`${AUDNEX_BASE_URL}/books/${normalizedAsin}/chapters`);
  url.searchParams.set('region', String(region || 'de').trim() || 'de');
  logger.info('chapters:fetch:start', { asin: normalizedAsin, url: url.toString() });

  const payload = await audnexFetch(url.toString());
  const chapters = extractChapterArray(payload)
    .map((entry, index) => normalizeAudnexChapter(entry, index))
    .filter((chapter) => chapter.endMs > chapter.startMs && chapter.title);

  logger.info('chapters:fetch:done', { asin: normalizedAsin, count: chapters.length });
  return chapters;
}

module.exports = {
  extractAsinFromAaxFile,
  fetchBookByAsin,
  fetchChaptersByAsin
};
