/*
 * Copyright (c) 2026 by Christian Kellner.
 * Licensed under Apache-2.0 with Commons Clause and Attribution/Naming Clause
 */

import { readFile } from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const FIXTURES_DIR = path.join(__dirname, 'testFixtures');

const testProviderConfig = JSON.parse(
  await readFile(new URL('./provider/testProvider.json', import.meta.url), 'utf-8'),
);

// hostname → providerName, built from testProvider.json
const hostnameToProvider = {};
// providerName → list page pathname (for distinguishing list vs detail URLs)
const providerListPath = {};

for (const [name, cfg] of Object.entries(testProviderConfig)) {
  if (!cfg.url) continue;
  try {
    const parsed = new URL(cfg.url);
    hostnameToProvider[parsed.hostname] = name;
    providerListPath[name] = parsed.pathname;
  } catch {
    // skip malformed URLs
  }
}

async function tryReadFile(filepath) {
  try {
    return await readFile(filepath, 'utf-8');
  } catch {
    return null;
  }
}

function withRealEstateType(data, realEstateType) {
  if (!realEstateType?.length || !Array.isArray(data?.resultListItems)) {
    return data;
  }

  const cloned = typeof structuredClone === 'function' ? structuredClone(data) : JSON.parse(JSON.stringify(data));
  for (const item of cloned.resultListItems) {
    if (item?.type === 'EXPOSE_RESULT' && item?.item) {
      item.item.realEstateType = realEstateType;
    }
  }
  return cloned;
}

/**
 * Returns fixture HTML for the given URL by mapping hostname → provider name,
 * then distinguishing list vs detail pages by comparing the URL path against
 * the configured list URL path from testProvider.json.
 */
export async function readFixture(url) {
  let hostname, pathname;
  try {
    const parsed = new URL(url);
    hostname = parsed.hostname;
    pathname = parsed.pathname;
  } catch {
    return null;
  }

  const providerName = hostnameToProvider[hostname];
  if (!providerName) return null;

  if (providerListPath[providerName] === pathname) {
    return tryReadFile(path.join(FIXTURES_DIR, `${providerName}.html`));
  }

  // Detail page: prefer dedicated detail fixture, fall back to list fixture
  const detailHtml = await tryReadFile(path.join(FIXTURES_DIR, `${providerName}_detail.html`));
  if (detailHtml) return detailHtml;
  return tryReadFile(path.join(FIXTURES_DIR, `${providerName}.html`));
}

/**
 * Returns a fetch replacement that intercepts immoscout mobile API calls and
 * serves pre-downloaded JSON fixtures. Throws for any other URL to prevent
 * accidental live network traffic in offline mode.
 */
export function buildFetchMock() {
  let listData = null;
  let detailData = null;

  return async (url) => {
    const urlStr = String(url);

    if (urlStr.includes('api.mobile.immobilienscout24.de/search/list')) {
      if (!listData) {
        const raw = await tryReadFile(path.join(FIXTURES_DIR, 'immoscout_list.json'));
        listData = raw ? JSON.parse(raw) : { resultListItems: [] };
      }

      const requestedType = new URL(urlStr).searchParams.get('realestatetype');
      const responseData = withRealEstateType(listData, requestedType);
      return { ok: true, status: 200, json: () => Promise.resolve(responseData) };
    }

    if (urlStr.includes('api.mobile.immobilienscout24.de/expose/')) {
      if (!detailData) {
        const raw = await tryReadFile(path.join(FIXTURES_DIR, 'immoscout_detail.json'));
        detailData = raw ? JSON.parse(raw) : { sections: [], contact: {} };
      }
      return { ok: true, status: 200, json: () => Promise.resolve(detailData) };
    }

    throw new Error(`Network request blocked in offline mode: ${urlStr}`);
  };
}
