import { normalizeText, uniqueBy } from "./utils.js";

export const OWNER_FIRST_STRATEGY_VERSION = "owner-first-v4";

const DEFAULT_NEGATIVES = "";

const UNIVERSAL_SIGNALS = [
  "owner operated",
  "family owned",
  "locally owned",
  "independently owned",
  "founder",
  "co-owner",
  "opened by",
  "founded by",
  "meet the owner",
  "our story",
  "under new ownership",
  "ribbon cutting",
  "grand opening",
  "owner interview",
  "chamber of commerce",
  "principal",
  "license holder",
  "qualifying party",
  "small business owner",
  "women owned",
  "veteran owned",
  "minority owned"
];

const OWNER_VISIBLE_SOURCE_FAMILIES = [
  "about team page",
  "founder story",
  "chamber ribbon cutting",
  "local press",
  "BBB principal profile",
  "state license board",
  "professional board profile",
  "contractor license board",
  "license record",
  "permit record",
  "booking vendor bio",
  "social bio",
  "professional directory"
];

const OWNER_VISIBLE_MODES = [
  "first-party-owner-page",
  "founder-story",
  "chamber-ribbon",
  "local-press",
  "bbb-principal",
  "state-license-board",
  "professional-board",
  "contractor-license-board",
  "license-record",
  "permit-record",
  "booking-bio",
  "social-bio",
  "professional-directory"
];

const NICHE_PROFILES = [
  {
    id: "restaurant",
    match: /\b(restaurants?|eatery|eateries|diner|food|bar|grill|taqueria|pizzeria|bistro|cafe|cafes)\b/i,
    terms: ["restaurant", "eatery", "bistro", "taqueria", "food truck", "supper club", "caterer"],
    archetypes: ["chef-owner", "family operator", "food truck to brick and mortar", "pop-up to permanent", "neighborhood restaurant"],
    events: ["new opening", "soft opening", "grand opening", "under new ownership", "anniversary", "restaurant week", "food festival"],
    sources: ["local food press", "chamber ribbon cutting", "liquor license", "food permit", "our story page", "community fundraiser"],
    modes: ["first-party-owner-page", "founder-story", "chamber-ribbon", "local-press", "bbb-principal", "license-record", "permit-record", "booking-bio", "social-bio", "professional-directory"],
    phrases: ["chef-owner", "husband and wife", "family recipe", "opened a restaurant", "brick and mortar", "neighborhood restaurant owner"]
  },
  {
    id: "bakery_cafe",
    match: /\b(bakeries|bakery|cafe|cafes|coffee|roaster|pastry|cake)\b/i,
    terms: ["bakery", "cafe", "coffee roaster", "microbakery", "cake studio", "farmers market baker"],
    archetypes: ["maker-owner", "home bakery to storefront", "roaster founder", "family bakery"],
    events: ["first storefront", "farmers market vendor", "grand opening", "wedding vendor", "artisan market"],
    sources: ["farmers market directory", "wedding vendor profile", "local food press", "chamber opening", "public social bio"],
    modes: ["first-party-owner-page", "founder-story", "chamber-ribbon", "local-press", "bbb-principal", "license-record", "permit-record", "booking-bio", "social-bio", "professional-directory"],
    phrases: ["baker-owner", "pastry chef owner", "from farmers market", "home bakery owner", "coffee roaster founder"]
  },
  {
    id: "salon",
    match: /\b(salons?|spa|nails?|lashes|barber|stylist|beauty|esthetician)\b/i,
    terms: ["salon", "nail salon", "beauty studio", "salon suite", "spa", "barber studio"],
    archetypes: ["owner-stylist", "suite owner", "independent nail artist", "esthetician founder"],
    events: ["opened her own studio", "new salon opening", "bridal vendor", "women owned studio", "ribbon cutting"],
    sources: ["cosmetology license", "booking bio", "Instagram bio", "chamber opening", "bridal directory"],
    modes: ["first-party-owner-page", "founder-story", "chamber-ribbon", "local-press", "bbb-principal", "state-license-board", "license-record", "booking-bio", "social-bio", "professional-directory"],
    phrases: ["owner stylist", "independent stylist", "salon owner", "suite owner", "owner esthetician"]
  },
  {
    id: "clinic",
    match: /\b(dentists?|dental|clinics?|doctor|medical|chiropractor|vet|veterinary)\b/i,
    terms: ["private practice", "clinic", "dental practice", "doctor owned clinic", "family dentistry"],
    archetypes: ["practitioner-owner", "solo practice", "doctor founder", "private practice owner"],
    events: ["opened own practice", "new office", "bought the practice", "community health sponsor"],
    sources: ["professional license", "NPI registry", "state dental board", "professional board profile", "practice about page", "local health publication", "chamber opening"],
    modes: ["first-party-owner-page", "founder-story", "chamber-ribbon", "local-press", "bbb-principal", "state-license-board", "professional-board", "license-record", "booking-bio", "social-bio", "professional-directory"],
    phrases: ["private practice owner", "doctor-owned", "solo practice", "practice founder", "opened her own practice"]
  },
  {
    id: "trades",
    match: /\b(plumbers?|plumbing|electrician|hvac|contractors?|roofers?|roofing|construction|repair|landscap|solar|pest)\b/i,
    terms: ["contractor", "plumber", "electrician", "HVAC company", "roofing company", "repair shop"],
    archetypes: ["licensed owner-operator", "master tradesperson", "family trade business", "one truck operator"],
    events: ["license holder", "permit applicant", "family business", "veteran owned", "home show exhibitor"],
    sources: ["contractor license", "contractor license board", "building permit", "BBB principal profile", "trade association", "community sponsor"],
    modes: ["first-party-owner-page", "founder-story", "chamber-ribbon", "local-press", "bbb-principal", "state-license-board", "contractor-license-board", "license-record", "permit-record", "social-bio", "professional-directory"],
    phrases: ["owner operated", "master plumber owner", "licensed contractor owner", "family owned", "owner answers the phone"]
  },
  {
    id: "fitness",
    match: /\b(gyms?|fitness|crossfit|boxing|pilates|yoga|trainer|martial arts)\b/i,
    terms: ["fitness studio", "gym", "yoga studio", "personal training studio", "boxing gym", "pilates studio"],
    archetypes: ["owner-coach", "trainer founder", "boutique studio owner", "garage gym to studio"],
    events: ["opened a studio", "community class", "ribbon cutting", "wellness event", "founder teaches classes"],
    sources: ["instructor bio", "class booking page", "wellness publication", "chamber opening", "public social bio"],
    modes: ["first-party-owner-page", "founder-story", "chamber-ribbon", "local-press", "bbb-principal", "booking-bio", "social-bio", "professional-directory"],
    phrases: ["owner coach", "studio founder", "trainer owned", "boutique fitness owner", "not a big box gym"]
  },
  {
    id: "creative_services",
    match: /\b(photographers?|videographers?|video|design|marketing|agency|web|seo|branding)\b/i,
    terms: ["photographer", "videographer", "design studio", "marketing agency", "web agency", "branding studio"],
    archetypes: ["founder studio owner", "solo operator", "husband and wife team", "boutique agency founder"],
    events: ["portfolio founder", "local award", "podcast interview", "wedding vendor profile", "case study"],
    sources: ["portfolio about page", "wedding vendor directory", "Clutch profile", "LinkedIn founder profile", "local award"],
    modes: ["first-party-owner-page", "founder-story", "local-press", "bbb-principal", "booking-bio", "social-bio", "professional-directory"],
    phrases: ["founder led", "boutique agency founder", "about the photographer", "principal designer", "owner portfolio"]
  },
  {
    id: "local_retail",
    match: /\b(retail|shop|store|boutique|bookstore|gift|auto|detailing|groomer|tutor|music|dance|school)\b/i,
    terms: ["local shop", "boutique", "auto repair", "mobile detailer", "pet groomer", "dance studio", "music school"],
    archetypes: ["maker-owner", "community embedded owner", "mobile operator", "founder instructor", "family retailer"],
    events: ["shop local feature", "main street member", "grand opening", "under new ownership", "event sponsor"],
    sources: ["main street directory", "chamber member", "local news", "public social bio", "association directory"],
    modes: ["first-party-owner-page", "founder-story", "chamber-ribbon", "local-press", "bbb-principal", "license-record", "booking-bio", "social-bio", "professional-directory"],
    phrases: ["shop owner", "locally owned", "owner instructor", "mobile owner operator", "family owned"]
  }
];

export function buildOwnerFirstDiscoveryPlan({ niche, location, maxAngles = 48 } = {}) {
  const profile = nicheProfileFor(niche);
  const place = normalizeText(location);
  const angles = [];
  const terms = uniqueBy([...(profile.terms || []), ...expandGenericTerms(niche)], (value) => value.toLowerCase());
  const signals = uniqueBy([...(profile.phrases || []), ...UNIVERSAL_SIGNALS], (value) => value.toLowerCase());
  const archetypes = profile.archetypes || ["owner-operated"];
  const events = profile.events || ["opening", "ribbon cutting", "under new ownership"];
  const sources = uniqueBy([...(profile.sources || []), ...OWNER_VISIBLE_SOURCE_FAMILIES], (value) => value.toLowerCase());
  const modes = ownerVisibleModesFor(profile);

  let index = 0;
  const push = ({ term, signal, source, event, archetype, mode, query }) => {
    const angle = {
      id: `owner-first-${profile.id}-${String(index + 1).padStart(2, "0")}`,
      strategyVersion: OWNER_FIRST_STRATEGY_VERSION,
      niche: profile.id,
      term,
      signal,
      source,
      event,
      archetype,
      location: place,
      signature: semanticSignature([profile.id, term, archetype, source, event, signal, mode]),
      mode,
      ownerEvidencePriority: ownerEvidencePriorityFor(mode),
      query: normalizeQuery(query || renderQuery({ term, signal, source, event, location: place, mode }))
    };
    index += 1;
    angles.push(angle);
  };

  for (let i = 0; angles.length < Math.min(maxAngles, modes.length); i += 1) {
    push({
      term: terms[i % terms.length],
      signal: signals[(i * 2) % signals.length],
      source: sources[i % sources.length],
      event: events[(i * 3) % events.length],
      archetype: archetypes[(i * 5) % archetypes.length],
      mode: modes[i]
    });
  }

  const modeCycle = [...modes, "relationship-led", "event-led", "source-led", "transition-led", "role-led"];
  for (let i = 0; angles.length < maxAngles && i < Math.max(terms.length, signals.length, events.length, sources.length) * 4; i += 1) {
    const term = terms[i % terms.length];
    const signal = signals[(i * 2) % signals.length];
    const source = sources[(i * 3) % sources.length];
    const event = events[(i * 5) % events.length];
    const archetype = archetypes[(i * 7) % archetypes.length];
    const mode = modeCycle[i % modeCycle.length];
    push({ term, signal, source, event, archetype, mode });
  }

  const deduped = diverseAngles(angles, maxAngles);
  return {
    version: OWNER_FIRST_STRATEGY_VERSION,
    principle: "Build an owner evidence graph first, then search the proven person's public contact trail before using broad business inventory fallback.",
    niche: profile.id,
    location: place,
    positiveSignals: signals.slice(0, 24),
    sourceFamilies: OWNER_VISIBLE_SOURCE_FAMILIES,
    rejectionSignals: [
      "franchise",
      "corporate",
      "store locator",
      "investor relations",
      "national chain",
      "multi-state locations",
      "central call center",
      "careers portal"
    ],
    angles: deduped
  };
}

export function buildOwnerFirstQueryVariants(niche, location, { maxQueries = 36, includeInventoryFallback = true } = {}) {
  const plan = buildOwnerFirstDiscoveryPlan({ niche, location, maxAngles: maxQueries + 10 });
  const ownerQueries = plan.angles.map((angle) => angle.query);
  const fallback = includeInventoryFallback ? inventoryFallbackQueries(niche, location).slice(0, 4) : [];
  return uniqueBy([...ownerQueries, ...fallback], (query) => query.toLowerCase()).slice(0, maxQueries);
}

export function ownerFirstFallbackSearchQueries(context = {}) {
  return buildOwnerFirstQueryVariants(context.niche || "local business", context.city || "United States", {
    maxQueries: 10,
    includeInventoryFallback: false
  });
}

function renderQuery({ term, signal, source, event, location, mode }) {
  const local = normalizeText(location);
  switch (mode) {
    case "first-party-owner-page":
      return `${local} ${term} "about" "team" owner founder "${signal}" ${DEFAULT_NEGATIVES}`;
    case "founder-story":
      return `${local} ${term} "founder story" OR "founded by" owner ${DEFAULT_NEGATIVES}`;
    case "chamber-ribbon":
      return `${local} ${term} "ribbon cutting" chamber owner ${DEFAULT_NEGATIVES}`;
    case "local-press":
      return `${local} ${term} "owner" "local news" interview ${DEFAULT_NEGATIVES}`;
    case "bbb-principal":
      return `${local} ${term} "BBB" "principal" owner ${DEFAULT_NEGATIVES}`;
    case "state-license-board":
      return `${local} ${term} "state license" "license holder" owner ${DEFAULT_NEGATIVES}`;
    case "professional-board":
      return `${local} ${term} "professional board" "license" owner principal ${DEFAULT_NEGATIVES}`;
    case "contractor-license-board":
      return `${local} ${term} "contractor license" "qualifying party" owner ${DEFAULT_NEGATIVES}`;
    case "license-record":
      return `${local} ${term} "license" owner principal ${DEFAULT_NEGATIVES}`;
    case "permit-record":
      return `${local} ${term} "permit" applicant owner ${DEFAULT_NEGATIVES}`;
    case "booking-bio":
      return `${local} ${term} "booking" "bio" owner founder ${DEFAULT_NEGATIVES}`;
    case "social-bio":
      return `${local} ${term} "Instagram" OR "Facebook" bio owner founder ${DEFAULT_NEGATIVES}`;
    case "professional-directory":
      return `${local} ${term} directory owner principal founder ${DEFAULT_NEGATIVES}`;
    case "event-led":
      return `${local} ${term} "${event}" owner ${DEFAULT_NEGATIVES}`;
    case "source-led":
      return `${local} ${term} ${source} owner ${DEFAULT_NEGATIVES}`;
    case "relationship-led":
      return `${local} "${signal}" ${term} owner ${DEFAULT_NEGATIVES}`;
    case "first-party-led":
      return `${local} ${term} "our story" "founder" ${DEFAULT_NEGATIVES}`;
    case "transition-led":
      return `${local} ${term} "under new ownership" founder ${DEFAULT_NEGATIVES}`;
    case "role-led":
    default:
      return `"${signal}" ${term} ${local} ${DEFAULT_NEGATIVES}`;
  }
}

function inventoryFallbackQueries(niche, location) {
  const profile = nicheProfileFor(niche);
  const terms = uniqueBy([...(profile.terms || []), ...expandGenericTerms(niche)], (term) => term.toLowerCase()).slice(0, 4);
  return terms.flatMap((term) => [
    `${term} ${location} official website owner`,
    `independent ${term} ${location}`
  ]);
}

function diverseAngles(angles, maxAngles) {
  const out = [];
  const seen = new Set();
  const sourceCounts = new Map();
  const eventCounts = new Map();
  for (const angle of [...angles].sort((a, b) => Number(b.ownerEvidencePriority || 0) - Number(a.ownerEvidencePriority || 0))) {
    if (!angle.query || seen.has(angle.signature)) continue;
    const sourceCount = sourceCounts.get(angle.source) || 0;
    const eventCount = eventCounts.get(angle.event) || 0;
    if (sourceCount >= Math.ceil(maxAngles * 0.25)) continue;
    if (eventCount >= Math.ceil(maxAngles * 0.2)) continue;
    seen.add(angle.signature);
    sourceCounts.set(angle.source, sourceCount + 1);
    eventCounts.set(angle.event, eventCount + 1);
    out.push(angle);
    if (out.length >= maxAngles) break;
  }
  if (out.length < maxAngles) {
    for (const angle of angles) {
      if (!angle.query || seen.has(angle.signature)) continue;
      seen.add(angle.signature);
      out.push(angle);
      if (out.length >= maxAngles) break;
    }
  }
  return out;
}

function ownerEvidencePriorityFor(mode) {
  const boosted = {
    "first-party-owner-page": 80,
    "bbb-principal": 78,
    "state-license-board": 76,
    "professional-board": 74,
    "contractor-license-board": 74,
    "founder-story": 72,
    "chamber-ribbon": 68,
    "local-press": 64
  };
  if (boosted[mode]) return boosted[mode];
  const index = OWNER_VISIBLE_MODES.indexOf(mode);
  if (index >= 0) return OWNER_VISIBLE_MODES.length - index + 10;
  if (["relationship-led", "event-led", "source-led", "transition-led", "role-led"].includes(mode)) return 5;
  return 1;
}

function ownerVisibleModesFor(profile = {}) {
  const fallbackModes = [
    "first-party-owner-page",
    "founder-story",
    "chamber-ribbon",
    "local-press",
    "bbb-principal",
    "license-record",
    "permit-record",
    "booking-bio",
    "social-bio",
    "professional-directory"
  ];
  return uniqueBy([...(profile.modes || fallbackModes), ...fallbackModes], (mode) => mode).filter((mode) => OWNER_VISIBLE_MODES.includes(mode));
}

function nicheProfileFor(niche) {
  const text = normalizeText(niche);
  return NICHE_PROFILES.find((profile) => profile.match.test(text)) || {
    id: "local_business",
    terms: expandGenericTerms(text),
    archetypes: ["practitioner-owner", "founder", "family operator", "community embedded owner"],
    events: ["grand opening", "ribbon cutting", "under new ownership", "local award", "community sponsor"],
    sources: ["local news", "chamber", "BBB", "first-party about page", "public social bio"],
    modes: ["first-party-owner-page", "founder-story", "chamber-ribbon", "local-press", "bbb-principal", "license-record", "permit-record", "booking-bio", "social-bio", "professional-directory"],
    phrases: ["owner operated", "founder", "family owned", "locally owned", "meet the owner"]
  };
}

function expandGenericTerms(niche) {
  const text = normalizeText(niche || "local business");
  const terms = [text];
  if (text.endsWith("s")) terms.push(text.slice(0, -1));
  terms.push(`independent ${text}`, `local ${text}`);
  return uniqueBy(terms.filter(Boolean), (term) => term.toLowerCase());
}

function renderQueryFragment(value) {
  return normalizeText(value).replace(/[^\w\s.-]+/g, " ").replace(/\s+/g, " ").trim();
}

function normalizeQuery(value) {
  return normalizeText(value)
    .replace(/\s+(-franchise|-chain|-corporate|-locations)/g, " $1")
    .replace(/\s+/g, " ")
    .trim();
}

function semanticSignature(parts) {
  return parts.map((part) => renderQueryFragment(part).toLowerCase()).filter(Boolean).join("|");
}
