import { SearchConfig } from '../types';
import { ab } from './ab';
import { randomDelay, humanize } from './anti-detection';

/**
 * Build a Reonomy search by driving the UI.
 * Takes a SearchConfig, navigates home, types location, selects from dropdown,
 * opens More Filters, applies each filter tab, clicks Apply.
 * Returns the search ID extracted from the resulting URL.
 */
export async function buildSearch(config: SearchConfig): Promise<string> {
  // Navigate to home
  ab('open "https://app.reonomy.com/#!/home"');
  await randomDelay(3000, 5000);

  // Type location into search box
  const snap = ab('snapshot -i');
  const searchBox = snap.output?.match(/(?:textbox|combobox) "(?:Search|Location|Type a location)[^"]*" \[ref=(e\d+)\]/);
  if (!searchBox) throw new Error('Could not find location search box');

  ab(`fill @${searchBox[1]} "${config.location}"`);
  await randomDelay(2000, 3000);

  // Select from dropdown — look for the matching option
  const dropSnap = ab('snapshot -i');
  const optionMatch = dropSnap.output?.match(
    new RegExp(`(?:option|listitem|button) "[^"]*${escapeRegex(config.location.split(',')[0])}[^"]*" \\[ref=(e\\d+)\\]`, 'i')
  );
  if (optionMatch) {
    ab(`click @${optionMatch[1]}`);
    await randomDelay(2000, 3000);
  } else {
    // Fallback: press Enter
    ab(`press @${searchBox[1]} Enter`);
    await randomDelay(2000, 3000);
  }

  // Wait for search results to start loading
  await randomDelay(3000, 5000);

  // Apply property type filters if specified
  if (config.propertyTypes && config.propertyTypes.length > 0) {
    await applyPropertyTypes(config.propertyTypes);
  }

  // Open More Filters if we have advanced filters
  const hasAdvancedFilters =
    config.building || config.owner || config.occupants ||
    config.sales || config.debt || config.distressed;

  if (hasAdvancedFilters) {
    await openMoreFilters();

    if (config.building) await applyBuildingFilters(config.building);
    if (config.owner) await applyOwnerFilters(config.owner);
    if (config.sales) await applySalesFilters(config.sales);
    if (config.debt) await applyDebtFilters(config.debt);

    // Click Apply
    await clickApply();
  }

  // Extract search ID from URL
  await randomDelay(3000, 5000);
  const urlResult = ab('eval "window.location.href"');
  const searchIdMatch = urlResult.output?.match(/search\/([a-f0-9-]+)/);
  if (!searchIdMatch) {
    throw new Error('Could not extract search ID from URL: ' + (urlResult.output || 'no URL'));
  }

  return searchIdMatch[1];
}

// ── Filter Helpers ──

async function applyPropertyTypes(types: string[]): Promise<void> {
  // Property types are usually checkboxes/buttons on the search page
  const snap = ab('snapshot -i');
  for (const type of types) {
    const typeMatch = snap.output?.match(
      new RegExp(`(?:checkbox|button) "${escapeRegex(type)}" \\[ref=(e\\d+)\\]`, 'i')
    );
    if (typeMatch) {
      ab(`click @${typeMatch[1]}`);
      await randomDelay(500, 1000);
    }
  }
  await randomDelay(1000, 2000);
}

async function openMoreFilters(): Promise<void> {
  const snap = ab('snapshot -i');
  const moreMatch = snap.output?.match(/button "More [Ff]ilters" \[ref=(e\d+)\]/);
  if (moreMatch) {
    ab(`click @${moreMatch[1]}`);
    await randomDelay(2000, 3000);
  }
}

async function clickApply(): Promise<void> {
  const snap = ab('snapshot -i');
  const applyMatch = snap.output?.match(/button "Apply" \[ref=(e\d+)\]/);
  if (applyMatch) {
    ab(`click @${applyMatch[1]}`);
    await randomDelay(3000, 5000);
  }
}

async function clickFilterTab(tabName: string): Promise<void> {
  const snap = ab('snapshot -i');
  const tabMatch = snap.output?.match(
    new RegExp(`(?:tab|button) "${escapeRegex(tabName)}" \\[ref=(e\\d+)\\]`, 'i')
  );
  if (tabMatch) {
    ab(`click @${tabMatch[1]}`);
    await randomDelay(1000, 2000);
  }
}

async function fillField(label: string, value: string | number): Promise<void> {
  const snap = ab('snapshot -i');
  const fieldMatch = snap.output?.match(
    new RegExp(`(?:textbox|spinbutton) "${escapeRegex(label)}" \\[ref=(e\\d+)\\]`, 'i')
  );
  if (fieldMatch) {
    ab(`fill @${fieldMatch[1]} "${value}"`);
    await randomDelay(300, 600);
  }
}

async function clickCheckbox(label: string): Promise<void> {
  const snap = ab('snapshot -i');
  const cbMatch = snap.output?.match(
    new RegExp(`(?:checkbox|switch) "${escapeRegex(label)}" \\[ref=(e\\d+)\\]`, 'i')
  );
  if (cbMatch) {
    ab(`click @${cbMatch[1]}`);
    await randomDelay(300, 600);
  }
}

// ── Building & Lot Filters ──

async function applyBuildingFilters(building: NonNullable<SearchConfig['building']>): Promise<void> {
  await clickFilterTab('Building & Lot');
  await humanize();

  if (building.yearBuiltFrom) await fillField('Year Built From', building.yearBuiltFrom);
  if (building.yearBuiltUntil) await fillField('Year Built Until', building.yearBuiltUntil);
  if (building.yearRenovatedFrom) await fillField('Year Renovated From', building.yearRenovatedFrom);
  if (building.yearRenovatedUntil) await fillField('Year Renovated Until', building.yearRenovatedUntil);
  if (building.totalUnitsMin) await fillField('Total Units Min', building.totalUnitsMin);
  if (building.totalUnitsMax) await fillField('Total Units Max', building.totalUnitsMax);
  if (building.buildingAreaMin) await fillField('Building Area Min', building.buildingAreaMin);
  if (building.buildingAreaMax) await fillField('Building Area Max', building.buildingAreaMax);
  if (building.lotSizeSfMin) await fillField('Lot Size SF Min', building.lotSizeSfMin);
  if (building.lotSizeSfMax) await fillField('Lot Size SF Max', building.lotSizeSfMax);
  if (building.lotSizeAcresMin) await fillField('Lot Size Acres Min', building.lotSizeAcresMin);
  if (building.lotSizeAcresMax) await fillField('Lot Size Acres Max', building.lotSizeAcresMax);
  if (building.opportunityZone) await clickCheckbox('Opportunity Zone');
}

// ── Owner Filters ──

async function applyOwnerFilters(owner: NonNullable<SearchConfig['owner']>): Promise<void> {
  await clickFilterTab('Owner');
  await humanize();

  if (owner.nameOrCompany) await fillField('Name or Company', owner.nameOrCompany);
  if (owner.includesPhone) await clickCheckbox('Includes Phone');
  if (owner.includesEmail) await clickCheckbox('Includes Email');
  if (owner.includesMailingAddress) await clickCheckbox('Includes Mailing Address');
  if (owner.portfolioMin) await fillField('Portfolio Min', owner.portfolioMin);
  if (owner.portfolioMax) await fillField('Portfolio Max', owner.portfolioMax);
  if (owner.ownerOccupied) await clickCheckbox('Owner Occupied');
  if (owner.inStateOwner) await clickCheckbox('In State Owner');
  if (owner.portfolioValueMin) await fillField('Portfolio Value Min', owner.portfolioValueMin);
  if (owner.portfolioValueMax) await fillField('Portfolio Value Max', owner.portfolioValueMax);
}

// ── Sales Filters ──

async function applySalesFilters(sales: NonNullable<SearchConfig['sales']>): Promise<void> {
  await clickFilterTab('Sales');
  await humanize();

  if (sales.priceMin) await fillField('Price Min', sales.priceMin);
  if (sales.priceMax) await fillField('Price Max', sales.priceMax);
  if (sales.pricePerSfMin) await fillField('Price Per SF Min', sales.pricePerSfMin);
  if (sales.pricePerSfMax) await fillField('Price Per SF Max', sales.pricePerSfMax);
  if (sales.likelyToSell) await clickCheckbox('Likely to Sell');
  if (sales.multiParcel) await clickCheckbox('Multi Parcel');
}

// ── Debt Filters ──

async function applyDebtFilters(debt: NonNullable<SearchConfig['debt']>): Promise<void> {
  await clickFilterTab('Debt');
  await humanize();

  if (debt.amountMin) await fillField('Amount Min', debt.amountMin);
  if (debt.amountMax) await fillField('Amount Max', debt.amountMax);
  if (debt.lenderName) await fillField('Lender Name', debt.lenderName);
  if (debt.cmbsLoan) await clickCheckbox('CMBS Loan');
}

// ── Utility ──

function escapeRegex(str: string): string {
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
