import * as cheerio from "cheerio";
import { Property } from "../types/property";
import { BaseScraper } from "./baseScraper";
import { VALENCIA_DISTRICTS } from "../config/valenciaDistricts";
import { ValenciaDistrictModel } from "../models/valenciaDistrictModel";

const MAX_PAGES = 5; // Máximo de páginas por zona
/** Tipos de propiedad con sus path en pisos.com */
const PISO_TYPES = ["pisos", "casas", "chalets"] as const;

// Caché de URLs base que devolvieron 404 — se omiten durante 48 h para no
// desperdiciar peticiones en zonas que no existen en pisos.com.
const pisos404Cache = new Map<string, number>(); // baseUrl → expiración (ms epoch)
const PISOS_404_TTL = 48 * 60 * 60 * 1000;       // 48 horas

export class PisosScraper extends BaseScraper {
  constructor() { super("https://www.pisos.com", "Pisos.com"); }
  private async getValenciaDistrictTargets(): Promise<Array<{ slug: string; zoneName: string }>> {
    try {
      const rows = await ValenciaDistrictModel.findAll();
      if (rows.length > 0) return rows
        .filter(r => r.active !== 0 && !!r.pisos_slug)
        .map(r => ({ slug: r.pisos_slug, zoneName: `${r.name}, Valencia` }));
    } catch { /* fallback */ }
    return VALENCIA_DISTRICTS.map(d => ({ slug: d.pisos, zoneName: `${d.name}, Valencia` }));
  }

  async scrape(): Promise<Property[]> {
    // Usa getActiveZones() para respetar el zone override (scraping por zona)
    const zones = await this.getActiveZones();
    let targets: Array<{ baseUrl: string; zoneName: string }> = [];

    const typesForOperation = this._operationType === "rent" ? (["pisos"] as const) : PISO_TYPES;
    if (zones.length > 0) {
      for (const z of zones) {
        const districtSlugs = z.slug === "valencia" ? await this.getValenciaDistrictTargets() : null;
        for (const type of typesForOperation) {
          if (districtSlugs) {
            for (const district of districtSlugs) {
              const districtLocationSlug = district.slug.replace(/^pisos-/, "");
              const districtTypeSlug = type === "pisos" ? district.slug : `${type}-${districtLocationSlug}`;
              const opPath = this._operationType === "rent" ? "alquiler" : "venta";
              targets.push({ baseUrl: `${this.baseUrl}/${opPath}/${districtTypeSlug}/`, zoneName: district.zoneName });
            }
          } else {
            // pisos_slug se usa sólo para el tipo pisos (puede ser personalizado, ej: "pisos-riba-roja-de-turia")
            // Para casas/chalets derivamos el slug de la parte de localidad de pisos_slug
            // (ej: "pisos-riba-roja-de-turia" → "casas-riba-roja-de-turia")
            const locationSlug = z.pisos_slug ? z.pisos_slug.replace(/^pisos-/, "") : z.slug;
            const slug = (type === "pisos" && z.pisos_slug) ? z.pisos_slug : `${type}-${locationSlug}`;
            const opPath = this._operationType === "rent" ? "alquiler" : "venta";
            targets.push({ baseUrl: `${this.baseUrl}/${opPath}/${slug}/`, zoneName: z.name });
          }
        }
      }
    } else {
      for (const type of typesForOperation) {
        const opPath = this._operationType === "rent" ? "alquiler" : "venta";
        targets.push({ baseUrl: `${this.baseUrl}/${opPath}/${type}-lliria/`, zoneName: "Llíria" });
      }
    }

    const all: Property[] = [];
    const seenUrls = new Set<string>();

    for (const { baseUrl, zoneName } of targets) {
      // Saltar zonas cacheadas como 404 hasta que expire el TTL
      const blocked404Until = pisos404Cache.get(baseUrl);
      if (blocked404Until && Date.now() < blocked404Until) {
        const remainHrs = Math.ceil((blocked404Until - Date.now()) / 3600000);
        console.log(`[Pisos.com] ${baseUrl} sin resultados conocidos, omitiendo (${remainHrs}h restantes)`);
        continue;
      }

      let pageCount = 0;

      for (let pageNum = 1; pageNum <= MAX_PAGES; pageNum++) {
        // Pisos.com usa /2/, /3/, ...; ?pagina=N canonicaliza a la página 1.
        const pageUrl = pageNum === 1 ? baseUrl : `${baseUrl}${pageNum}/`;
        const html = await this.fetchHtml(pageUrl);
        if (!html) {
          // Si la primera página da 404 u otro error, cachear la URL base 48 h
          if (pageNum === 1) {
            console.log(`[Pisos.com] Cacheando ${baseUrl} como 404 durante 48h`);
            pisos404Cache.set(baseUrl, Date.now() + PISOS_404_TTL);
          }
          break;
        }

        const $ = cheerio.load(html);
        let found = 0;

        // Pisos.com 2024: cards con clase ad-preview o li.ad-preview-item
        $("[class*='ad-preview'], .ad-item, article, li[class*='list-item']").each((_i, el) => {
          const operationDetailPath = this._operationType === "rent" ? "/alquilar/" : "/comprar/";
          const linkEl = $(el).find(`a[href*='${operationDetailPath}'], a[href*='/anuncio_inmobiliaria/']`).first();
          const title = this.sanitizeText(
            linkEl.text().trim().split("\n")[0] ||
            $(el).find("h2, h3, [class*='title']").first().text() ||
            `Propiedad en ${zoneName}`
          );
          const priceRaw = $(el).find("[class*='price'], .price, [class*='Price']").first().text();
          const price = this.parsePrice(priceRaw);
          const href = linkEl.attr("href") || "";
          if (!href || !price) return;
          const url2 = href.startsWith("http") ? href : `${this.baseUrl}${href}`;
          if (seenUrls.has(url2)) return;
          seenUrls.add(url2);
          const location = this.sanitizeText($(el).find(".location, [class*='location']").first().text() || zoneName);
          const rooms = parseInt($(el).find("[class*='hab'], [class*='room']").first().text()) || 0;
          const size_m2 = parseInt($(el).find("[class*='m2'], [class*='metros']").first().text()) || 0;
          const image_url = $(el).find("img").attr("src") || $(el).find("img").attr("data-src") || "";
          all.push({
            title, price, location,
            municipality: this.detectMunicipality(location + " " + zoneName, zones, zoneName),
            property_type: this.normalizeType(title),
            operation_type: this._operationType,
            rooms, size_m2, url: url2, source: this.sourceName, image_url,
          });
          found++;
        });

        pageCount++;
        if (found < 3) break; // Probable última página
      }

      console.log(`[${this.sourceName}] ${zoneName}: ${pageCount} páginas, ${seenUrls.size} únicos hasta ahora`);
    }

    return this.validateResults(all);
  }

}
