export interface MobileSchemaDetectionResult {
  hasLocalBusinessSchema: boolean;
  hasMobileSpecificSchema: boolean;
  detectedTypes: string[];
  missingRecommended: string[];
}

const MOBILE_PRIORITY_TYPES = [
  "LocalBusiness",
  "MedicalWebPage",
  "Physician",
  "Dentist",
  "LegalService",
  "HomeAndConstructionBusiness",
  "AutoDealer",
  "Restaurant",
  "Hotel",
  "Product",
  "Service",
  "FAQPage",
  "HowTo",
  "SpeakableSpecification",
];

const LOCAL_BUSINESS_SUBTYPES = new Set([
  "LocalBusiness",
  "MedicalOrganization",
  "Physician",
  "Dentist",
  "Hospital",
  "LegalService",
  "Lawyer",
  "Attorney",
  "HomeAndConstructionBusiness",
  "Plumber",
  "Electrician",
  "GeneralContractor",
  "AutoDealer",
  "AutoRepair",
  "Restaurant",
  "FoodEstablishment",
  "Hotel",
  "LodgingBusiness",
  "HealthAndBeautyBusiness",
  "SportsActivityLocation",
  "FinancialService",
]);

export function detectMobileSpecificSchema(domHtml: string): MobileSchemaDetectionResult {
  const detectedTypes: string[] = [];

  // Extract @type values from JSON-LD blocks
  const jsonLdBlocks = domHtml.match(
    /<script[^>]+type=["']application\/ld\+json["'][^>]*>([\s\S]*?)<\/script>/gi,
  );

  if (jsonLdBlocks) {
    for (const block of jsonLdBlocks) {
      const inner = block.replace(/<script[^>]*>/i, "").replace(/<\/script>/i, "").trim();
      try {
        const parsed = JSON.parse(inner);
        const typeValues = extractTypes(parsed);
        for (const t of typeValues) {
          if (!detectedTypes.includes(t)) detectedTypes.push(t);
        }
      } catch {
        // Malformed JSON-LD -- skip
        const typeMatches = inner.matchAll(/"@type"\s*:\s*"([^"]+)"/g);
        for (const m of typeMatches) {
          if (!detectedTypes.includes(m[1])) detectedTypes.push(m[1]);
        }
      }
    }
  }

  // Also check microdata itemtype attributes
  const microdataMatches = domHtml.matchAll(/itemtype=["']https?:\/\/schema\.org\/([^"'\s]+)["']/gi);
  for (const m of microdataMatches) {
    if (!detectedTypes.includes(m[1])) detectedTypes.push(m[1]);
  }

  const hasLocalBusinessSchema = detectedTypes.some((t) => LOCAL_BUSINESS_SUBTYPES.has(t));
  const hasMobileSpecificSchema =
    hasLocalBusinessSchema ||
    detectedTypes.some((t) => ["FAQPage", "HowTo", "SpeakableSpecification"].includes(t));

  const missingRecommended = MOBILE_PRIORITY_TYPES.filter(
    (t) => !detectedTypes.includes(t),
  ).slice(0, 4);

  return { hasLocalBusinessSchema, hasMobileSpecificSchema, detectedTypes, missingRecommended };
}

function extractTypes(obj: unknown): string[] {
  if (!obj || typeof obj !== "object") return [];
  const types: string[] = [];
  if (Array.isArray(obj)) {
    for (const item of obj) types.push(...extractTypes(item));
    return types;
  }
  const record = obj as Record<string, unknown>;
  if (record["@type"]) {
    const t = record["@type"];
    if (typeof t === "string") types.push(t);
    else if (Array.isArray(t)) types.push(...t.filter((v): v is string => typeof v === "string"));
  }
  for (const val of Object.values(record)) {
    if (val && typeof val === "object") types.push(...extractTypes(val));
  }
  return types;
}
