export function extractZillowStructuredPhotoCandidatesFromNextDataScript(scriptText) {
  if (typeof scriptText !== "string" || !scriptText.trim()) {
    return [];
  }

  let nextData;
  try {
    nextData = JSON.parse(scriptText);
  } catch {
    return [];
  }

  const cacheText = nextData?.props?.pageProps?.componentProps?.gdpClientCache;
  if (typeof cacheText !== "string" || !cacheText.trim()) {
    return [];
  }

  let cache;
  try {
    cache = JSON.parse(cacheText);
  } catch {
    return [];
  }

  const out = [];

  for (const entry of Object.values(cache)) {
    const photos = entry?.property?.responsivePhotos;
    if (!Array.isArray(photos)) continue;

    for (const photo of photos) {
      if (typeof photo?.url === "string" && photo.url) {
        out.push({ url: photo.url });
        continue;
      }

      const mixedSources = photo?.mixedSources;
      if (!mixedSources || typeof mixedSources !== "object") continue;

      let best = null;
      for (const variants of Object.values(mixedSources)) {
        if (!Array.isArray(variants)) continue;
        for (const variant of variants) {
          if (typeof variant?.url !== "string" || !variant.url) continue;
          const width = Number(variant.width || 0);
          if (!best || width > best.width) {
            best = { url: variant.url, width };
          }
        }
      }

      if (best) {
        out.push(best);
      }
    }
  }

  return out;
}

function collapseIdentifier(value) {
  return String(value || "").replace(/\s+/g, " ").trim();
}

function isLikelyIdentifier(value) {
  return /^[A-Z0-9-]{4,40}$/i.test(collapseIdentifier(value));
}

function visitForIdentifierHints(node, hints) {
  if (!node || typeof node !== "object") return;
  if (Array.isArray(node)) {
    for (const item of node) {
      visitForIdentifierHints(item, hints);
    }
    return;
  }

  for (const [key, value] of Object.entries(node)) {
    const normalizedKey = key.toLowerCase();
    if ((normalizedKey === "parcelid" || normalizedKey === "parcelnumber") && hints.parcelId == null) {
      if (typeof value === "string" || typeof value === "number") {
        const candidate = collapseIdentifier(value);
        if (isLikelyIdentifier(candidate)) {
          hints.parcelId = candidate;
        }
      }
    }
    if ((normalizedKey === "apn" || normalizedKey === "apnnumber" || normalizedKey === "taxparcelid" || normalizedKey === "taxid") && hints.apn == null) {
      if (typeof value === "string" || typeof value === "number") {
        const candidate = collapseIdentifier(value);
        if (isLikelyIdentifier(candidate)) {
          hints.apn = candidate;
        }
      }
    }

    if (value && typeof value === "object") {
      visitForIdentifierHints(value, hints);
    }
  }
}

export function extractZillowIdentifierHintsFromNextDataScript(scriptText) {
  if (typeof scriptText !== "string" || !scriptText.trim()) {
    return {};
  }

  let nextData;
  try {
    nextData = JSON.parse(scriptText);
  } catch {
    return {};
  }

  const hints = {};
  visitForIdentifierHints(nextData, hints);

  const cacheText = nextData?.props?.pageProps?.componentProps?.gdpClientCache;
  if (typeof cacheText === "string" && cacheText.trim()) {
    try {
      visitForIdentifierHints(JSON.parse(cacheText), hints);
    } catch {
      // Ignore cache parse failures; base next-data parse already succeeded.
    }
  }

  return hints;
}

export function extractZillowIdentifierHintsFromText(text) {
  const source = typeof text === "string" ? text : "";
  const hints = {};

  const parcelMatch = source.match(/\b(?:parcel|parcel number|parcel #|tax parcel)(?:\s*(?:number|#|no\.?))?\s*[:#]?\s*([A-Z0-9-]{4,40})\b/i);
  if (parcelMatch) {
    hints.parcelId = collapseIdentifier(parcelMatch[1]);
  }

  const apnMatch = source.match(/\b(?:apn|apn #|apn no\.?|tax id)(?:\s*(?:number|#|no\.?))?\s*[:#]?\s*([A-Z0-9-]{4,40})\b/i);
  if (apnMatch) {
    hints.apn = collapseIdentifier(apnMatch[1]);
  }

  return hints;
}

const DEFAULT_MINIMUM_TRUSTED_STRUCTURED_PHOTO_COUNT = 12;

export function shouldUseStructuredZillowPhotos(candidates, options = {}) {
  const count = Array.isArray(candidates) ? candidates.length : 0;
  const normalizedOptions =
    typeof options === "number"
      ? { expectedPhotoCount: options }
      : options && typeof options === "object"
        ? options
        : {};
  const expectedPhotoCount = Number(normalizedOptions.expectedPhotoCount || 0);
  const fallbackPhotoCount = Number(normalizedOptions.fallbackPhotoCount || 0);
  const minimumTrustCount = Number(
    normalizedOptions.minimumTrustCount || DEFAULT_MINIMUM_TRUSTED_STRUCTURED_PHOTO_COUNT
  );

  if (Number.isFinite(expectedPhotoCount) && expectedPhotoCount > 0) {
    return count >= expectedPhotoCount;
  }

  if (Number.isFinite(fallbackPhotoCount) && fallbackPhotoCount > 0) {
    return count >= fallbackPhotoCount;
  }

  return count >= minimumTrustCount;
}
