<?php
/**
 * Plugin Name: Ledak
 * Version: 2.0.2
 */

if (!defined('ABSPATH')) exit;

/* =========================
 * Helpers: site context
 * ========================= */
function ledak88_get_context(): array {
  $brand_name       = sanitize_text_field( get_option('seo_brand_name', '') );
  if ($brand_name === '') $brand_name = get_bloginfo('name');

  $meta_keywords    = sanitize_text_field( get_option('seo_meta_keywords', '') );
  $meta_description = wp_strip_all_tags( get_option('seo_meta_description', ''), true );
  if ($meta_description === '') $meta_description = get_bloginfo('description');

  $register_url_opt = (string) get_option('register_url', '/register');

  // canonical home (no query)
  $brand_url = home_url('/');

  // --- Custom Logo (dynamic) ---
  $logo_id  = (int) get_theme_mod('custom_logo');
  $logo_url = '';
  $logo_w   = 0;
  $logo_h   = 0;

  if ($logo_id) {
    $img = wp_get_attachment_image_src($logo_id, 'full'); // [url, w, h]
    if ($img) {
      $logo_url = esc_url_raw($img[0]);
      $logo_w   = (int) $img[1];
      $logo_h   = (int) $img[2];
    }
  }
  // Fallback: Site Icon atau path default
  if (!$logo_url) {
    $fallback = get_site_icon_url(512);
    if ($fallback) {
      $logo_url = esc_url_raw($fallback);
      $logo_w   = 512;
      $logo_h   = 512;
    } else {
      $logo_url = $brand_url . 'wp-content/uploads/2025/09/Slot-8-16-2025-1-300x300.png';
      $logo_w   = 1023;
      $logo_h   = 270;
    }
  }

  // --- Primary Image dari Rank Math OpenGraph (homepage) ---
  $primary_img   = '';
  $primary_img_w = 0;
  $primary_img_h = 0;

  // halaman depan (static front page kalau diset)
  $front_id = (int) get_option('page_on_front');
  if (!$front_id) $front_id = get_queried_object_id();

  // 1) Per-page OG Rank Math (meta post)
  if ($front_id) {
    $rm_og_id  = (int) get_post_meta($front_id, 'rank_math_facebook_image_id', true);
    $rm_og_url = (string) get_post_meta($front_id, 'rank_math_facebook_image', true);

    if ($rm_og_id) {
      $img = wp_get_attachment_image_src($rm_og_id, 'full');
      if ($img) {
        $primary_img   = esc_url_raw($img[0]);
        $primary_img_w = (int) $img[1];
        $primary_img_h = (int) $img[2];
      }
    } elseif (!empty($rm_og_url) && filter_var($rm_og_url, FILTER_VALIDATE_URL)) {
      $primary_img = esc_url_raw($rm_og_url);
    }
  }

  // 2) Global OG dari pengaturan Rank Math
  if (!$primary_img) {
    $rm_titles = get_option('rank-math-options-titles');
    if (is_array($rm_titles)) {
      foreach (['homepage_facebook_image_id','home_facebook_image_id','facebook_image_id','open_graph_image_id'] as $k) {
        if (!empty($rm_titles[$k])) {
          $img = wp_get_attachment_image_src( (int) $rm_titles[$k], 'full');
          if ($img) {
            $primary_img   = esc_url_raw($img[0]);
            $primary_img_w = (int) $img[1];
            $primary_img_h = (int) $img[2];
            break;
          }
        }
      }
      if (!$primary_img) {
        foreach (['homepage_facebook_image','home_facebook_image','facebook_image','open_graph_image'] as $k) {
          if (!empty($rm_titles[$k]) && filter_var($rm_titles[$k], FILTER_VALIDATE_URL)) {
            $primary_img = esc_url_raw($rm_titles[$k]);
            break;
          }
        }
      }
    }
  }

  // 3) Featured image halaman depan
  if (!$primary_img && $front_id) {
    $thumb_id = get_post_thumbnail_id($front_id);
    if ($thumb_id) {
      $img = wp_get_attachment_image_src($thumb_id, 'full');
      if ($img) {
        $primary_img   = esc_url_raw($img[0]);
        $primary_img_w = (int) $img[1];
        $primary_img_h = (int) $img[2];
      }
    }
  }

  // 4) Fallback terakhir
  if (!$primary_img) {
    $site_icon = get_site_icon_url(512);
    if ($site_icon) {
      $primary_img   = esc_url_raw($site_icon);
      $primary_img_w = 512;
      $primary_img_h = 512;
    } else {
      $primary_img = $brand_url . 'wp-content/uploads/2025/02/situs_utama.png';
    }
  }

  $author_img  = 'https://secure.gravatar.com/avatar/9bdcf8bde35b2c78188e374ead5d384753db22a1e35d93da48484759ad7f0852?s=96&d=wavatar&r=g';

  $register_url = (strpos($register_url_opt, 'http') === 0)
    ? esc_url_raw($register_url_opt)
    : esc_url_raw( $brand_url . ltrim($register_url_opt, '/') );

  // safer title untuk homepage walau di luar Loop
  $front_id    = get_queried_object_id();
  $front_title = $front_id ? get_the_title($front_id) : get_bloginfo('name');
  $seo_headline = wp_strip_all_tags(
    html_entity_decode( function_exists('wp_get_document_title') ? wp_get_document_title() : $front_title, ENT_QUOTES, 'UTF-8' )
  );

  return [
    'brand_name'       => $brand_name,
    'brand_url'        => untrailingslashit($brand_url), // no trailing slash
    'meta_keywords'    => $meta_keywords,
    'meta_description' => $meta_description,
    'register_url'     => $register_url,
    'logo_url'         => esc_url_raw($logo_url),
    'logo_width'       => $logo_w,
    'logo_height'      => $logo_h,
    'primary_img'      => esc_url_raw($primary_img),
    'primary_img_w'    => $primary_img_w,
    'primary_img_h'    => $primary_img_h,
    'author_img'       => esc_url_raw($author_img),
    'front_title'      => wp_strip_all_tags($front_title),
    'seo_headline'     => $seo_headline,
    'date_published'   => '2025-02-12T09:35:15+07:00',
    'date_modified'    => '2025-09-28T23:02:22+07:00',
  ];
}

/* ==========================================================
 * FIX: Force schema field types (prevents mixed-type issues)
 * - ensures isAccessibleForFree is ALWAYS boolean
 * ========================================================== */
function ledak88_schema_force_types($value) {
  $to_bool = function($v) {
    if (is_bool($v)) return $v;
    if (is_int($v)) return $v === 1;
    if (is_float($v)) return ((int)$v) === 1;
    if (is_string($v)) {
      $vv = strtolower(trim($v));
      if ($vv === 'true' || $vv === '1' || $vv === 'yes') return true;
      if ($vv === 'false' || $vv === '0' || $vv === 'no') return false;
    }
    return (bool)$v;
  };

  $walk = function($node) use (&$walk, $to_bool) {
    if (is_array($node)) {
      foreach ($node as $k => $v) {
        if ($k === 'isAccessibleForFree') {
          $node[$k] = $to_bool($v); // ALWAYS boolean
          continue;
        }
        $node[$k] = $walk($v);
      }
    }
    return $node;
  };

  return $walk($value);
}

/* =========================================
 *  IMPROVED: Build @graph for Homepage
 *  - Added PrimaryImage node
 *  - Added BreadcrumbList node
 *  - Added Logo Dimensions
 * ========================================= */
function ledak88_custom_graph_nodes(): array {
    // Retrieve context for dynamic data
    $c = ledak88_get_context();
    $brand_name = $c['brand_name'];
    $base_url = $c['brand_url']; 

    // 1. Primary Image Object (Required by WebPage)
    $primary_image_node = [
        "@type" => "ImageObject",
        "@id" => $base_url . "/#primaryimage",
        "url" => $c['primary_img'],
        "contentUrl" => $c['primary_img'],
        "width" => $c['primary_img_w'],
        "height" => $c['primary_img_h'],
        "caption" => $brand_name
    ];

    // 2. BreadcrumbList (Required for Rich Results validation)
    $breadcrumb_node = [
        "@type" => "BreadcrumbList",
        "@id" => $base_url . "/#breadcrumb",
        "itemListElement" => [
            [
                "@type" => "ListItem",
                "position" => 1,
                "name" => "Home",
                "item" => $base_url . "/"
            ]
        ]
    ];

    // Get contact info for organization address
    $ci = ledak88_extract_contact_from_page();
    $address_array = [
        "@type" => "PostalAddress",
        "addressCountry" => "ID"
    ];
    
    // Add address details if available
    if (!empty($ci['streetAddress'])) {
        $address_array['streetAddress'] = $ci['streetAddress'];
    }
    if (!empty($ci['addressLocality'])) {
        $address_array['addressLocality'] = $ci['addressLocality'];
    }
    if (!empty($ci['postalCode'])) {
        $address_array['postalCode'] = $ci['postalCode'];
    }

    // 3. Organization (Enhanced for all pages)
    $org_node = [
        "@type" => "Organization",
        "@id" => $base_url . "/#organization",
        "name" => $brand_name,
        "url" => $base_url . "/",
        "logo" => [
            "@type" => "ImageObject",
            "url" => $c['logo_url'],
            "width" => $c['logo_width'],
            "height" => $c['logo_height'],
            "caption" => $brand_name . " Logo"
        ],
        "description" => $brand_name . " hadir sebagai platform hiburan digital dengan pendekatan informatif, transparan, dan ramah pengguna.",
        "sameAs" => [],
        "contactPoint" => [
            "@type" => "ContactPoint",
            "contactType" => "customer support",
            "areaServed" => "ID",
            "availableLanguage" => "Indonesian"
        ],
        // Enhanced properties for Google Rich Results
        "foundingDate" => "2025",
        "founder" => [
            "@type" => "Person",
            "name" => "Tim " . $brand_name
        ],
        "numberOfEmployees" => [
            "@type" => "QuantitativeValue",
            "value" => "50"
        ],
        "address" => $address_array,
        "brand" => [
            "@type" => "Brand",
            "name" => $brand_name
        ]
    ];

    // 4. WebSite
    $website_node = [
        "@type" => "WebSite",
        "@id" => $base_url . "/#website",
        "url" => $base_url . "/",
        "name" => $brand_name . ": Panduan Andal Memahami Platform Hiburan Digital",
        "description" => "Pelajari manfaat, fitur, dan cara penggunaan bertanggung jawab di " . $brand_name . ".",
        "publisher" => [
            "@id" => $base_url . "/#organization"
        ],
        "potentialAction" => [
            "@type" => "SearchAction",
            "target" => [
                "@type" => "EntryPoint",
                "urlTemplate" => $base_url . "/?s={search_term_string}"
            ],
            "query-input" => "required name=search_term_string"
        ]
    ];

    // 5. WebPage
    $webpage_node = [
        "@type" => "WebPage",
        "@id" => $base_url . "/#webpage",
        "url" => $base_url . "/",
        "name" => $brand_name . ": Panduan Andal Memahami Platform Hiburan Digital",
        "description" => $brand_name . " hadir sebagai platform hiburan digital dengan pendekatan informatif, transparan, dan ramah pengguna. Pelajari manfaat, fitur, dan cara penggunaan bertanggung jawab.",
        "isPartOf" => [
            "@id" => $base_url . "/#website"
        ],
        "about" => [
            "@id" => $base_url . "/#organization"
        ],
        "primaryImageOfPage" => [
            "@id" => $base_url . "/#primaryimage" // References the ImageObject node above
        ],
        "image" => [
             "@id" => $base_url . "/#primaryimage"
        ],
        "datePublished" => "2026-01-16",
        "dateModified" => "2026-01-16",
        "inLanguage" => "id-ID",
        "breadcrumb" => [
            "@id" => $base_url . "/#breadcrumb" // References the BreadcrumbList node above
        ]
    ];

    // 6. FAQPage
    $faq_node = [
        "@type" => "FAQPage",
        "@id"   => $base_url . "/#faq",
        "mainEntity" => [
            [
                "@type" => "Question",
                "name" => "Apa itu " . $brand_name . "?",
                "acceptedAnswer" => [
                    "@type" => "Answer",
                    "text" => $brand_name . " adalah panduan andal untuk memahami platform hiburan digital, menyediakan informasi yang transparan dan pendekatan ramah pengguna bagi mereka yang ingin mempelajari fitur dan penggunaannya secara bertanggung jawab."
                ]
            ],
            [
                "@type" => "Question",
                "name" => "Apa saja fitur utama yang dijelaskan di " . $brand_name . "?",
                "acceptedAnswer" => [
                    "@type" => "Answer",
                    "text" => $brand_name . " menjelaskan berbagai manfaat dan fitur platform hiburan digital dengan fokus pada transparansi data dan pengalaman pengguna yang optimal."
                ]
            ],
            [
                "@type" => "Question",
                "name" => "Bagaimana cara menggunakan platform " . $brand_name . " dengan bertanggung jawab?",
                "acceptedAnswer" => [
                    "@type" => "Answer",
                    "text" => "Platform ini memberikan panduan lengkap mengenai cara penggunaan yang bertanggung jawab, memastikan pengguna memahami mekanisme dan manfaatnya secara utuh."
                ]
            ]
        ]
    ];

    // Combine all nodes
    $graph = [
        $org_node,
        $website_node,
        $primary_image_node, // Added to graph
        $breadcrumb_node,    // Added to graph
        $webpage_node,
        $faq_node
    ];

    // ✅ FIX: force types
    $graph = ledak88_schema_force_types($graph);

    return $graph;
}

/* =======================================
 * [NEW] Build @graph for single Posts
 * ======================================= */
function ledak88_post_graph_nodes(int $post_id): array {
  $c     = ledak88_get_context();
  $home  = $c['brand_url']; // no trailing slash
  $brand = $c['brand_name'];

  $post = get_post($post_id);
  if (!$post || $post->post_status !== 'publish') return [];

  $url   = get_permalink($post_id);
  if (!$url) return [];

  // Title / description
  $title = wp_strip_all_tags(get_the_title($post_id));
  $desc  = '';

  if (has_excerpt($post_id)) {
    $desc = wp_strip_all_tags(get_the_excerpt($post_id));
  } else {
    $desc = wp_strip_all_tags( wp_trim_words( wp_strip_all_tags($post->post_content), 30, '' ) );
  }
  if ($desc === '') $desc = $c['meta_description'];

  // Dates
  $date_published = get_post_time('c', true, $post);
  $date_modified  = get_post_modified_time('c', true, $post);

  // Featured image
  $img_url = '';
  $img_w = 0; $img_h = 0;
  $thumb_id = get_post_thumbnail_id($post_id);
  if ($thumb_id) {
    $img = wp_get_attachment_image_src($thumb_id, 'full');
    if ($img) {
      $img_url = esc_url_raw($img[0]);
      $img_w   = (int) $img[1];
      $img_h   = (int) $img[2];
    }
  }
  if (!$img_url) {
    $img_url = $c['primary_img'];
    $img_w   = (int) $c['primary_img_w'];
    $img_h   = (int) $c['primary_img_h'];
  }

  // Author
  $author_id   = (int) $post->post_author;
  $author_name = $author_id ? (string) get_the_author_meta('display_name', $author_id) : $brand;
  if ($author_name === '') $author_name = $brand;

  $author_url = $author_id ? get_author_posts_url($author_id) : ($home . '/author/' . sanitize_title($brand) . '/');
  $author_img = $author_id ? get_avatar_url($author_id, ['size' => 96]) : $c['author_img'];
  if (!$author_img) $author_img = $c['author_img'];

  $author_node_id = $url . '#author';

  // Breadcrumb: Home > Category (optional) > Post
  $itemListElement = [
    [ '@type'=>'ListItem', 'position'=>1, 'name'=>'Home', 'item'=> $home . '/' ],
  ];
  $pos = 2;

  $cats = get_the_category($post_id);
  if (!empty($cats) && !is_wp_error($cats)) {
    // Use first category (simple, stable)
    $cat = $cats[0];
    $cat_link = get_category_link($cat);
    if ($cat_link && !is_wp_error($cat_link)) {
      $itemListElement[] = [ '@type'=>'ListItem', 'position'=>$pos++, 'name'=> wp_strip_all_tags($cat->name), 'item'=> esc_url_raw($cat_link) ];
    }
  }
  $itemListElement[] = [ '@type'=>'ListItem', 'position'=>$pos++, 'name'=> $title, 'item'=> $url ];

  $breadcrumb = [
    '@type' => 'BreadcrumbList',
    '@id'   => $url . '#breadcrumb',
    'itemListElement' => $itemListElement,
  ];

  // Primary image for this post
  $primaryimage = [
    '@type' => 'ImageObject',
    '@id'   => $url . '#primaryimage',
    'url'   => esc_url_raw($img_url),
    'contentUrl' => esc_url_raw($img_url),
    'caption' => esc_html($title),
  ];
  if (!empty($img_w) && !empty($img_h)) {
    $primaryimage['width']  = (int) $img_w;
    $primaryimage['height'] = (int) $img_h;
  }

  // Get contact info for organization address
  $ci = ledak88_extract_contact_from_page();
  $address_array = [
      "@type" => "PostalAddress",
      "addressCountry" => "ID"
  ];
  
  // Add address details if available
  if (!empty($ci['streetAddress'])) {
      $address_array['streetAddress'] = $ci['streetAddress'];
  }
  if (!empty($ci['addressLocality'])) {
      $address_array['addressLocality'] = $ci['addressLocality'];
  }
  if (!empty($ci['postalCode'])) {
      $address_array['postalCode'] = $ci['postalCode'];
  }

  // Organization node (enhanced for all pages)
  $org_node = [
    '@type' => 'Organization',
    '@id'   => $home . '/#organization',
    'name' => $brand,
    'url' => $home . '/',
    'logo' => [
        '@type' => 'ImageObject',
        'url' => $c['logo_url'],
        'width' => $c['logo_width'],
        'height' => $c['logo_height'],
        'caption' => $brand . ' Logo'
    ],
    'description' => $brand . ' hadir sebagai platform hiburan digital dengan pendekatan informatif, transparan, dan ramah pengguna.',
    'sameAs' => [],
    'contactPoint' => [
        '@type' => 'ContactPoint',
        'contactType' => 'customer support',
        'areaServed' => 'ID',
        'availableLanguage' => 'Indonesian'
    ],
    // Enhanced properties for Google Rich Results
    'foundingDate' => '2025',
    'founder' => [
        '@type' => 'Person',
        'name' => 'Tim ' . $brand
    ],
    'numberOfEmployees' => [
        '@type' => 'QuantitativeValue',
        'value' => '50'
    ],
    'address' => $address_array,
    'brand' => [
        '@type' => 'Brand',
        'name' => $brand
    ]
  ];

  // WebPage node for this post
  $webpage = [
    '@type' => 'WebPage',
    '@id'   => $url . '#webpage',
    'url'   => $url,
    'name'  => $title,
    'isPartOf' => [ '@id' => $home . '/#website' ],
    'about'    => [ '@id' => $home . '/#organization' ],
    'primaryImageOfPage' => [ '@id' => $url . '#primaryimage' ],
    'image'    => [ '@id' => $url . '#primaryimage' ],
    'thumbnailUrl' => esc_url_raw($img_url),
    'datePublished' => $date_published,
    'dateModified'  => $date_modified,
    'description'   => $desc,
    'breadcrumb'    => [ '@id' => $url . '#breadcrumb' ],
    'inLanguage' => 'id-ID',
    'potentialAction' => [[ '@type' => 'ReadAction', 'target' => [ $url ] ]],
    'headline' => $title,
    'author'   => [ '@id' => $author_node_id ],
    'publisher'=> [ '@id' => $home . '/#organization' ],
    'mainEntityOfPage' => [ '@type' => 'WebPage', '@id' => $url ],
  ];

  // Author node (post-specific) — safe, avoids interfering with homepage author node
  $author_node = [
    '@type' => 'Person',
    '@id'   => $author_node_id,
    'name'  => wp_strip_all_tags($author_name),
    'url'   => esc_url_raw($author_url),
    'image' => [
      '@type' => 'ImageObject',
      'url'   => esc_url_raw($author_img),
      'width' => 96,
      'height'=> 96,
    ],
  ];

  // Article / BlogPosting (Enhanced for Google Rich Results)
  $article = [
    '@type' => ['Article','BlogPosting'],
    '@id'   => $url . '#article',
    'headline'     => $title,
    'description'  => $desc,
    'url'          => $url,
    'mainEntityOfPage' => [ '@id' => $url . '#webpage' ],
    'author'       => [ '@id' => $author_node_id ],
    'publisher'    => [ '@id' => $home . '/#organization' ],
    'datePublished'=> $date_published,
    'dateModified' => $date_modified,
    'inLanguage' => 'id-ID',
    'image' => [ '@id' => $url . '#primaryimage' ],
    // Enhanced properties
    'articleSection' => !empty($cats) ? wp_strip_all_tags($cats[0]->name) : 'General',
    'keywords' => $c['meta_keywords'],
    'wordCount' => str_word_count(wp_strip_all_tags($post->post_content)),
    'speakable' => [
        '@type' => 'SpeakableSpecification',
        'cssSelector' => ['.entry-content', '.post-content', '.article-content']
    ]
  ];

  $graph = [$org_node, $primaryimage, $breadcrumb, $author_node, $webpage, $article];

  // ✅ FIX: force types
  $graph = ledak88_schema_force_types($graph);

  return $graph;
}

/* =======================================
 * NEW: Build @graph for regular Pages
 * ======================================= */
function ledak88_page_graph_nodes(int $page_id): array {
  $c     = ledak88_get_context();
  $home  = $c['brand_url']; // no trailing slash
  $brand = $c['brand_name'];

  $page = get_post($page_id);
  if (!$page || $page->post_status !== 'publish') return [];

  $url   = get_permalink($page_id);
  if (!$url) return [];

  // Title / description
  $title = wp_strip_all_tags(get_the_title($page_id));
  $desc  = '';

  if (has_excerpt($page_id)) {
    $desc = wp_strip_all_tags(get_the_excerpt($page_id));
  } else {
    $desc = wp_strip_all_tags( wp_trim_words( wp_strip_all_tags($page->post_content), 30, '' ) );
  }
  if ($desc === '') $desc = $c['meta_description'];

  // Dates
  $date_published = get_post_time('c', true, $page);
  $date_modified  = get_post_modified_time('c', true, $page);

  // Featured image
  $img_url = '';
  $img_w = 0; $img_h = 0;
  $thumb_id = get_post_thumbnail_id($page_id);
  if ($thumb_id) {
    $img = wp_get_attachment_image_src($thumb_id, 'full');
    if ($img) {
      $img_url = esc_url_raw($img[0]);
      $img_w   = (int) $img[1];
      $img_h   = (int) $img[2];
    }
  }
  if (!$img_url) {
    $img_url = $c['primary_img'];
    $img_w   = (int) $c['primary_img_w'];
    $img_h   = (int) $c['primary_img_h'];
  }

  // Breadcrumb: Home > Page
  $breadcrumb = [
    '@type' => 'BreadcrumbList',
    '@id'   => $url . '#breadcrumb',
    'itemListElement' => [
      ['@type'=>'ListItem','position'=>1,'name'=>'Home','item'=>$home . '/'],
      ['@type'=>'ListItem','position'=>2,'name'=>$title,'item'=>$url],
    ],
  ];

  // Primary image for this page
  $primaryimage = [
    '@type' => 'ImageObject',
    '@id'   => $url . '#primaryimage',
    'url'   => esc_url_raw($img_url),
    'contentUrl' => esc_url_raw($img_url),
    'caption' => esc_html($title),
  ];
  if (!empty($img_w) && !empty($img_h)) {
    $primaryimage['width']  = (int) $img_w;
    $primaryimage['height'] = (int) $img_h;
  }

  // Get contact info for organization address
  $ci = ledak88_extract_contact_from_page();
  $address_array = [
      "@type" => "PostalAddress",
      "addressCountry" => "ID"
  ];
  
  // Add address details if available
  if (!empty($ci['streetAddress'])) {
      $address_array['streetAddress'] = $ci['streetAddress'];
  }
  if (!empty($ci['addressLocality'])) {
      $address_array['addressLocality'] = $ci['addressLocality'];
  }
  // Postal code is optional, only add if it exists
  if (!empty($ci['postalCode'])) {
      $address_array['postalCode'] = $ci['postalCode'];
  }

  // Organization node (enhanced for all pages)
  $org_node = [
    '@type' => 'Organization',
    '@id'   => $home . '/#organization',
    'name' => $brand,
    'url' => $home . '/',
    'logo' => [
        '@type' => 'ImageObject',
        'url' => $c['logo_url'],
        'width' => $c['logo_width'],
        'height' => $c['logo_height'],
        'caption' => $brand . ' Logo'
    ],
    'description' => $brand . ' hadir sebagai platform hiburan digital dengan pendekatan informatif, transparan, dan ramah pengguna.',
    'sameAs' => [],
    'contactPoint' => [
        '@type' => 'ContactPoint',
        'contactType' => 'customer support',
        'areaServed' => 'ID',
        'availableLanguage' => 'Indonesian'
    ],
    // Enhanced properties for Google Rich Results
    'foundingDate' => '2025',
    'founder' => [
        '@type' => 'Person',
        'name' => 'Tim ' . $brand
    ],
    'numberOfEmployees' => [
        '@type' => 'QuantitativeValue',
        'value' => '50'
    ],
    'address' => $address_array,
    'brand' => [
        '@type' => 'Brand',
        'name' => $brand
    ]
  ];

  // WebPage node for this page
  $webpage = [
    '@type' => 'WebPage',
    '@id'   => $url . '#webpage',
    'url'   => $url,
    'name'  => $title,
    'isPartOf' => [ '@id' => $home . '/#website' ],
    'about'    => [ '@id' => $home . '/#organization' ],
    'primaryImageOfPage' => [ '@id' => $url . '#primaryimage' ],
    'image'    => [ '@id' => $url . '#primaryimage' ],
    'thumbnailUrl' => esc_url_raw($img_url),
    'datePublished' => $date_published,
    'dateModified'  => $date_modified,
    'description'   => $desc,
    'breadcrumb'    => [ '@id' => $url . '#breadcrumb' ],
    'inLanguage' => 'id-ID',
    'potentialAction' => [[ '@type' => 'ReadAction', 'target' => [ $url ] ]],
    'headline' => $title,
    'publisher'=> [ '@id' => $home . '/#organization' ],
    'mainEntityOfPage' => [ '@type' => 'WebPage', '@id' => $url ],
  ];

  $graph = [$org_node, $primaryimage, $breadcrumb, $webpage];

  // ✅ FIX: force types
  $graph = ledak88_schema_force_types($graph);

  return $graph;
}

/* =======================================
 * Merge helper: de-dupe by @id (ours win)
 * ======================================= */
function ledak88_merge_graphs(array $base_graph, array $custom_graph): array {
  $indexed = [];
  $push = static function($node) use (&$indexed) {
    if (is_array($node) && isset($node['@id']) && is_string($node['@id']) && $node['@id'] !== '') {
      $indexed[$node['@id']] = $node; // ours override
    } else {
      $indexed[] = $node;
    }
  };
  foreach ($base_graph as $n) $push($n);
  foreach ($custom_graph as $n) $push($n);
  return array_values($indexed);
}

/* =====================================================
 * Fallback: Rank Math not loaded → still print schema
 * ===================================================== */
if (!defined('RANK_MATH_VERSION') && !class_exists('RankMath')) {
  add_action('wp_head', function () {
    // homepage
    if (is_front_page()) {
      $payload = [
        '@context' => 'https://schema.org',
        '@graph'   => ledak88_custom_graph_nodes(),
      ];
      $payload = ledak88_schema_force_types($payload);
      echo "\n<script type=\"application/ld+json\">" .
        wp_json_encode($payload, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE) .
        "</script>\n";
      return;
    }

    // ✅ single posts
    if (is_singular('post')) {
      $post_id = get_queried_object_id();
      $graph = ledak88_post_graph_nodes((int)$post_id);
      if (!empty($graph)) {
        $payload = ['@context'=>'https://schema.org','@graph'=>$graph];
        $payload = ledak88_schema_force_types($payload);
        echo "\n<script type=\"application/ld+json\">".
          wp_json_encode($payload, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE).
          "</script>\n";
      }
      return;
    }

    // ✅ regular pages (excluding about and contact pages)
    if (is_page() && !is_page(['tentang-kami', 'kontak-kami'])) {
      $page_id = get_queried_object_id();
      $graph = ledak88_page_graph_nodes((int)$page_id);
      if (!empty($graph)) {
        $payload = ['@context'=>'https://schema.org','@graph'=>$graph];
        $payload = ledak88_schema_force_types($payload);
        echo "\n<script type=\"application/ld+json\">".
          wp_json_encode($payload, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE).
          "</script>\n";
      }
      return;
    }

    // ✅ Connect about schema to /tentang-kami page
    if (is_page('tentang-kami')) {
      $payload = ['@context'=>'https://schema.org','@graph'=>ledak88_about_graph_nodes()];
      $payload = ledak88_schema_force_types($payload);
      echo "\n<script type=\"application/ld+json\">".wp_json_encode($payload, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE)."</script>\n";
    }

    // ✅ Connect contact schema to /kontak-kami page
    if (is_page('kontak-kami')) {
      $payload = ['@context'=>'https://schema.org','@graph'=>ledak88_contact_graph_nodes()];
      $payload = ledak88_schema_force_types($payload);
      echo "\n<script type=\"application/ld+json\">".wp_json_encode($payload, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE)."</script>\n";
    }
  }, 99);
}

/* =====================================================
 * Remove Rank Math nodes that we replace (avoid dupes)
 * ===================================================== */
add_filter('rank_math/json_ld', function($data) {
  // homepage rules
  if (is_front_page()) {
    $conflict = ['WebPage','WebSite','Organization','BreadcrumbList','ImageObject','Article','FAQPage','Person','Question','Answer','ItemList','Product'];
    $filtered = [];
    foreach ((array)$data as $node) {
      if (!is_array($node)) { $filtered[] = $node; continue; }
      $types = $node['@type'] ?? null;
      $types = is_array($types) ? $types : ($types ? [$types] : []);
      if (!array_intersect($types, $conflict)) $filtered[] = $node;
    }
    return $filtered;
  }

  // ✅ single post rules (remove only what we override)
  if (is_singular('post')) {
    $conflict = ['WebPage','BreadcrumbList','ImageObject','Article','BlogPosting','Person','Organization'];
    $filtered = [];
    foreach ((array)$data as $node) {
      if (!is_array($node)) { $filtered[] = $node; continue; }
      $types = $node['@type'] ?? null;
      $types = is_array($types) ? $types : ($types ? [$types] : []);
      if (!array_intersect($types, $conflict)) $filtered[] = $node;
    }
    return $filtered;
  }

  // ✅ regular pages rules (remove only what we override)
  if (is_page() && !is_page(['tentang-kami', 'kontak-kami'])) {
    $conflict = ['WebPage','BreadcrumbList','ImageObject','Organization'];
    $filtered = [];
    foreach ((array)$data as $node) {
      if (!is_array($node)) { $filtered[] = $node; continue; }
      $types = $node['@type'] ?? null;
      $types = is_array($types) ? $types : ($types ? [$types] : []);
      if (!array_intersect($types, $conflict)) $filtered[] = $node;
    }
    return $filtered;
  }

  return $data;
}, 10);

/* ==============================================
 * Final merge right before Rank Math outputs
 * ============================================== */
add_filter('rank_math/json_ld_output', function($data) {
  // homepage merge
  if (is_front_page()) {
    $context        = $data['@context'] ?? 'https://schema.org';
    $existing_graph = isset($data['@graph']) && is_array($data['@graph']) ? $data['@graph'] : [];
    $custom_graph   = ledak88_custom_graph_nodes();

    $merged_graph = ledak88_merge_graphs($existing_graph, $custom_graph);

    // deep clean empties (remove null/''/empty arrays)
    $clean = function($n) use (&$clean) {
      if (!is_array($n)) return $n;
      foreach ($n as $k => $v) {
        if (is_array($v)) $n[$k] = $clean($v);
        if ($v === '' || $v === null || (is_array($v) && $v === [])) unset($n[$k]);
      }
      return $n;
    };
    $merged_graph = array_map($clean, $merged_graph);

    $out = ['@context' => $context, '@graph' => $merged_graph];
    $out = ledak88_schema_force_types($out); // ✅ FIX: enforce field types at final output
    return $out;
  }

  // ✅ single posts merge
  if (is_singular('post')) {
    $context        = $data['@context'] ?? 'https://schema.org';
    $existing_graph = isset($data['@graph']) && is_array($data['@graph']) ? $data['@graph'] : [];

    $post_id = (int) get_queried_object_id();
    $custom_graph = ledak88_post_graph_nodes($post_id);

    $merged_graph = ledak88_merge_graphs($existing_graph, $custom_graph);

    // deep clean empties (remove null/''/empty arrays)
    $clean = function($n) use (&$clean) {
      if (!is_array($n)) return $n;
      foreach ($n as $k => $v) {
        if (is_array($v)) $n[$k] = $clean($v);
        if ($v === '' || $v === null || (is_array($v) && $v === [])) unset($n[$k]);
      }
      return $n;
    };
    $merged_graph = array_map($clean, $merged_graph);

    $out = ['@context' => $context, '@graph' => $merged_graph];
    $out = ledak88_schema_force_types($out); // ✅ FIX
    return $out;
  }

  // ✅ regular pages merge (excluding about and contact pages)
  if (is_page() && !is_page(['tentang-kami', 'kontak-kami'])) {
    $context        = $data['@context'] ?? 'https://schema.org';
    $existing_graph = isset($data['@graph']) && is_array($data['@graph']) ? $data['@graph'] : [];

    $page_id = (int) get_queried_object_id();
    $custom_graph = ledak88_page_graph_nodes($page_id);

    $merged_graph = ledak88_merge_graphs($existing_graph, $custom_graph);

    // deep clean empties (remove null/''/empty arrays)
    $clean = function($n) use (&$clean) {
      if (!is_array($n)) return $n;
      foreach ($n as $k => $v) {
        if (is_array($v)) $n[$k] = $clean($v);
        if ($v === '' || $v === null || (is_array($v) && $v === [])) unset($n[$k]);
      }
      return $n;
    };
    $merged_graph = array_map($clean, $merged_graph);

    $out = ['@context' => $context, '@graph' => $merged_graph];
    $out = ledak88_schema_force_types($out);
    return $out;
  }

  // ✅ Connect about schema to /tentang-kami page with Rank Math
  if (is_page('tentang-kami')) {
    $context        = $data['@context'] ?? 'https://schema.org';
    $existing_graph = isset($data['@graph']) && is_array($data['@graph']) ? $data['@graph'] : [];
    $custom_graph   = ledak88_about_graph_nodes();

    $merged_graph = ledak88_merge_graphs($existing_graph, $custom_graph);

    // deep clean empties (remove null/''/empty arrays)
    $clean = function($n) use (&$clean) {
      if (!is_array($n)) return $n;
      foreach ($n as $k => $v) {
        if (is_array($v)) $n[$k] = $clean($v);
        if ($v === '' || $v === null || (is_array($v) && $v === [])) unset($n[$k]);
      }
      return $n;
    };
    $merged_graph = array_map($clean, $merged_graph);

    $out = ['@context' => $context, '@graph' => $merged_graph];
    $out = ledak88_schema_force_types($out);
    return $out;
  }

  // ✅ Connect contact schema to /kontak-kami page with Rank Math
  if (is_page('kontak-kami')) {
    $context        = $data['@context'] ?? 'https://schema.org';
    $existing_graph = isset($data['@graph']) && is_array($data['@graph']) ? $data['@graph'] : [];
    $custom_graph   = ledak88_contact_graph_nodes();

    $merged_graph = ledak88_merge_graphs($existing_graph, $custom_graph);

    // deep clean empties (remove null/''/empty arrays)
    $clean = function($n) use (&$clean) {
      if (!is_array($n)) return $n;
      foreach ($n as $k => $v) {
        if (is_array($v)) $n[$k] = $clean($v);
        if ($v === '' || $v === null || (is_array($v) && $v === [])) unset($n[$k]);
      }
      return $n;
    };
    $merged_graph = array_map($clean, $merged_graph);

    $out = ['@context' => $context, '@graph' => $merged_graph];
    $out = ledak88_schema_force_types($out);
    return $out;
  }

  return $data;
}, 20);

/* ==========================================================
 * [NEW] JSON-LD for /tentang-kami (AboutPage) & /kontak-kami (ContactPage)
 * ========================================================== */

/** Parse contact dari Rank Math option jadi array sederhana */
function ledak88_parse_rankmath_contact(): array {
  $raw = get_option('rank_math_contact_info', '');
  $out = ['emails'=>[], 'phones'=>[], 'address'=>'', 'hours'=>[]];

  // normalize ke array k=>v
  $arr = [];
  if (is_array($raw)) {
    $arr = $raw;
  } else {
    $lines = preg_split('/\r\n|\r|\n/', (string)$raw);
    foreach ($lines as $line) {
      if (strpos($line, ':') !== false) {
        [$k,$v] = array_map('trim', explode(':', $line, 2));
        if ($k !== '') $arr[strtolower($k)] = $v;
      }
    }
  }

  foreach ($arr as $k => $v) {
    $k = strtolower((string)$k);
    $v = trim((string)$v);
    if ($v === '') continue;

    if (strpos($k, 'email') !== false) {
      $mail = sanitize_email($v);
      if ($mail) $out['emails'][] = $mail;
    } elseif (strpos($k, 'wa') !== false || strpos($k, 'tel') === 0 || strpos($k, 'phone') !== false || strpos($k, 'telepon') !== false) {
      $out['phones'][] = preg_replace('/[^0-9+\-\s()]/', '', $v);
    } elseif (strpos($k, 'alamat') !== false || strpos($k, 'address') !== false) {
      $out['address'] = $v;
    } elseif (strpos($k, 'jam') !== false || strpos($k, 'hour') !== false) {
      $out['hours'][] = $v;
    }
  }

  // unik & bersih
  $out['emails'] = array_values(array_filter(array_unique($out['emails'])));
  $out['phones'] = array_values(array_filter(array_unique($out['phones'])));
  $out['hours']  = array_values(array_filter(array_unique($out['hours'])));

  return $out;
}

/** Enhanced function to extract contact information from kontak-kami page content with better address parsing */
function ledak88_extract_contact_from_page(): array {
  $page_id = get_page_by_path('kontak-kami');
  $contact_info = [
    'emails' => [],
    'phones' => [],
    'streetAddress' => '',
    'addressLocality' => '',
    'postalCode' => '',
    'address' => '',
    'hours' => []
  ];

  if (!$page_id) {
    return $contact_info;
  }

  $page = get_post($page_id);
  if (!$page || !$page->post_content) {
    return $contact_info;
  }

  // Get both stripped content and full HTML content
  $stripped_content = wp_strip_all_tags($page->post_content);
  $html_content = $page->post_content;
  
  // Extract email addresses
  preg_match_all('/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/', $stripped_content, $email_matches);
  if (!empty($email_matches[0])) {
    foreach ($email_matches[0] as $email) {
      $sanitized_email = sanitize_email($email);
      if ($sanitized_email && !in_array($sanitized_email, $contact_info['emails'])) {
        $contact_info['emails'][] = $sanitized_email;
      }
    }
  }

  // Extract phone numbers (Indonesian format: +62, 08, 021, etc.)
  preg_match_all('/(?:\+?62|0)[\d\-\(\)\s]{8,15}/', $stripped_content, $phone_matches);
  if (!empty($phone_matches[0])) {
    foreach ($phone_matches[0] as $phone) {
      $clean_phone = preg_replace('/[^0-9+\-\s()]/', '', $phone);
      if ($clean_phone && !in_array($clean_phone, $contact_info['phones'])) {
        $contact_info['phones'][] = $clean_phone;
      }
    }
  }

  // Parse HTML content to find postal codes in various formats
  // Postal codes can appear in different ways in HTML
  
  // Method 1: Look for postal code in common Indonesian formats
  $postal_patterns = [
    // Format: 12345 (5 digit number)
    '/\b\d{5}\b/',
    // Format: Kode Pos: 12345
    '/[Kk]ode\s*[Pp]os\s*[:\.]?\s*(\d{5})/',
    // Format: Pos: 12345
    '/[Pp]os\s*[:\.]?\s*(\d{5})/',
    // Format: Postal: 12345
    '/[Pp]ostal\s*[:\.]?\s*(\d{5})/',
    // Format: ZIP: 12345
    '/[Zz][Ii][Pp]\s*[:\.]?\s*(\d{5})/',
    // In HTML tags with postal code context
    '/<[^>]*>[^<]*[Kk]ode\s*[Pp]os[^<]*(\d{5})[^<]*<\/[^>]*>/',
    '/<[^>]*>[^<]*[Pp]os[^<]*(\d{5})[^<]*<\/[^>]*>/',
  ];
  
  foreach ($postal_patterns as $pattern) {
    if (preg_match($pattern, $html_content, $matches)) {
      // Get the last match (should be the postal code)
      $last_match = end($matches);
      if (is_numeric($last_match) && strlen($last_match) == 5) {
        $contact_info['postalCode'] = $last_match;
        break;
      }
    }
  }
  
  // Method 2: Also check stripped content
  if (empty($contact_info['postalCode'])) {
    if (preg_match('/\b\d{5}\b/', $stripped_content, $matches)) {
      $contact_info['postalCode'] = $matches[0];
    }
  }

  // Enhanced address parsing
  $lines = explode("\n", $stripped_content);
  
  // Process each line to find address components
  foreach ($lines as $line) {
    $line = trim($line);
    if (empty($line)) continue;
    
    // Look for street address (usually starts with Jl., Jalan, etc.)
    if (preg_match('/^(Jl\.?|Jalan|Jl\s|Street|St\.?)\s+/i', $line) && empty($contact_info['streetAddress'])) {
      $contact_info['streetAddress'] = $line;
    }
    
    // Look for locality (city name with area)
    elseif (preg_match('/(Jakarta|Bandung|Surabaya|Medan|Semarang|Yogyakarta|Denpasar|Makassar|Palembang|Balikpapan)\s*(Barat|Timur|Selatan|Utara|Pusat)?/i', $line) && empty($contact_info['addressLocality'])) {
      $contact_info['addressLocality'] = $line;
    }
    
    // If line doesn't match specific patterns but looks like an address line
    elseif (strlen($line) > 10 && strlen($line) < 100 && empty($contact_info['address'])) {
      // Check if it contains address-like words
      $address_indicators = ['jalan', 'jl', 'no.', 'rt', 'rw', 'kelurahan', 'kecamatan', 'kota', 'kabupaten', 'provinsi'];
      $line_lower = strtolower($line);
      $found_indicator = false;
      
      foreach ($address_indicators as $indicator) {
        if (strpos($line_lower, $indicator) !== false) {
          $found_indicator = true;
          break;
        }
      }
      
      if ($found_indicator) {
        $contact_info['address'] = $line;
      }
    }
  }

  // If we found structured address parts but no full address, construct it
  if (empty($contact_info['address']) && 
      (!empty($contact_info['streetAddress']) || 
       !empty($contact_info['addressLocality']))) {
    
    $address_parts = [];
    if (!empty($contact_info['streetAddress'])) $address_parts[] = $contact_info['streetAddress'];
    if (!empty($contact_info['addressLocality'])) $address_parts[] = $contact_info['addressLocality'];
    if (!empty($contact_info['postalCode'])) $address_parts[] = $contact_info['postalCode'];
    
    if (!empty($address_parts)) {
      $contact_info['address'] = implode(', ', $address_parts);
    }
  }
  
  // If we have full address but missing components, try to parse it
  if (!empty($contact_info['address']) && 
      (empty($contact_info['streetAddress']) || 
       empty($contact_info['addressLocality']))) {
    
    // Try to extract street address (first line usually)
    $addr_lines = explode(',', $contact_info['address']);
    if (empty($contact_info['streetAddress']) && !empty($addr_lines[0])) {
      $contact_info['streetAddress'] = trim($addr_lines[0]);
    }
    
    // Try to extract locality (look for city names)
    if (empty($contact_info['addressLocality'])) {
      foreach ($addr_lines as $addr_line) {
        $addr_line = trim($addr_line);
        if (preg_match('/(Jakarta|Bandung|Surabaya|Medan|Semarang|Yogyakarta|Denpasar|Makassar|Palembang|Balikpapan)\s*(Barat|Timur|Selatan|Utara|Pusat)?/i', $addr_line)) {
          $contact_info['addressLocality'] = $addr_line;
          break;
        }
      }
    }
  }

  // Extract business hours
  $hours_indicators = ['jam', 'hour', 'buka', 'open', 'tutup', 'close', 'operasional', 'senin', 'selasa', 'rabu', 'kamis', 'jumat', 'sabtu', 'minggu'];
  foreach ($lines as $line) {
    $line_lower = strtolower(trim($line));
    foreach ($hours_indicators as $indicator) {
      if (strpos($line_lower, $indicator) !== false && strlen(trim($line)) > 5) {
        $contact_info['hours'][] = trim($line);
      }
    }
  }

  // Also check for Rank Math contact info as fallback
  $rankmath_contact = ledak88_parse_rankmath_contact();
  
  // Merge with priority to page content
  if (empty($contact_info['emails']) && !empty($rankmath_contact['emails'])) {
    $contact_info['emails'] = $rankmath_contact['emails'];
  }
  
  if (empty($contact_info['phones']) && !empty($rankmath_contact['phones'])) {
    $contact_info['phones'] = $rankmath_contact['phones'];
  }
  
  if (empty($contact_info['address']) && !empty($rankmath_contact['address'])) {
    $contact_info['address'] = $rankmath_contact['address'];
  }
  
  if (empty($contact_info['hours']) && !empty($rankmath_contact['hours'])) {
    $contact_info['hours'] = $rankmath_contact['hours'];
  }

  // If still no postal code, try to extract from Rank Math address
  if (empty($contact_info['postalCode']) && !empty($rankmath_contact['address'])) {
    if (preg_match('/\b\d{5}\b/', $rankmath_contact['address'], $matches)) {
      $contact_info['postalCode'] = $matches[0];
    }
  }

  return $contact_info;
}

/** Build nodes untuk AboutPage (/tentang-kami) - Enhanced for Google Rich Results */
function ledak88_about_graph_nodes(): array {
  $c     = ledak88_get_context();
  $home  = $c['brand_url'];        // no trailing slash
  $brand = $c['brand_name'];
  $url   = home_url('/tentang-kami/');

  $breadcrumb = [
    '@type' => 'BreadcrumbList',
    '@id'   => $url . '#breadcrumb',
    'itemListElement' => [
      ['@type'=>'ListItem','position'=>1,'name'=>'Home','item'=>$home . '/'],
      ['@type'=>'ListItem','position'=>2,'name'=>'Tentang Kami','item'=>$url],
    ],
  ];

  // Get page content for description
  $page_id = get_page_by_path('tentang-kami');
  $page_description = $c['meta_description'];
  $page_content = '';
  if ($page_id) {
    $page = get_post($page_id);
    if ($page && $page->post_excerpt) {
      $page_description = wp_strip_all_tags($page->post_excerpt);
    } elseif ($page && $page->post_content) {
      $page_content = wp_strip_all_tags($page->post_content);
      $page_description = wp_strip_all_tags(wp_trim_words($page_content, 30, ''));
    }
  }

  // Get contact info for organization address
  $ci = ledak88_extract_contact_from_page();
  $address_array = [
      "@type" => "PostalAddress",
      "addressCountry" => "ID"
  ];
  
  // Add address details if available
  if (!empty($ci['streetAddress'])) {
      $address_array['streetAddress'] = $ci['streetAddress'];
  }
  if (!empty($ci['addressLocality'])) {
      $address_array['addressLocality'] = $ci['addressLocality'];
  }
  // Postal code is optional, only add if it exists
  if (!empty($ci['postalCode'])) {
      $address_array['postalCode'] = $ci['postalCode'];
  }

  // Organization node with enhanced properties
  $org_node = [
    '@type' => 'Organization',
    '@id'   => $home . '/#organization',
    'name' => $brand,
    'url' => $home . '/',
    'logo' => [
        '@type' => 'ImageObject',
        'url' => $c['logo_url'],
        'width' => $c['logo_width'],
        'height' => $c['logo_height'],
        'caption' => $brand . ' Logo'
    ],
    'description' => $brand . ' hadir sebagai platform hiburan digital dengan pendekatan informatif, transparan, dan ramah pengguna.',
    'sameAs' => [],
    'contactPoint' => [
        '@type' => 'ContactPoint',
        'contactType' => 'customer support',
        'areaServed' => 'ID',
        'availableLanguage' => 'Indonesian'
    ],
    // Enhanced properties for Google Rich Results
    'foundingDate' => '2025',
    'founder' => [
        '@type' => 'Person',
        'name' => 'Tim ' . $brand
    ],
    'numberOfEmployees' => [
        '@type' => 'QuantitativeValue',
        'value' => '50'
    ],
    'address' => $address_array,
    'brand' => [
        '@type' => 'Brand',
        'name' => $brand
    ]
  ];

  // Enhanced AboutPage with FAQ
  $webpage = [
    '@type' => ['WebPage','AboutPage'],
    '@id'   => $url . '#webpage',
    'url'   => $url,
    'name'  => 'Tentang ' . $brand,
    'isPartOf' => [ '@id' => $home . '/#website' ],
    'about'    => [ '@id' => $home . '/#organization' ],
    'primaryImageOfPage' => [ '@id' => $home . '/#primaryimage' ],
    'image'    => [ '@id' => $home . '/#primaryimage' ],
    'breadcrumb' => [ '@id' => $url . '#breadcrumb' ],
    'inLanguage'=> 'id-ID',
    'description' => $page_description,
    'headline'    => 'Tentang ' . $brand,
    'dateModified'=> $c['date_modified'],
    'mainEntityOfPage' => [ '@type' => 'WebPage', '@id' => $url ],
    'publisher'  => [ '@id' => $home . '/#organization' ],
    'author'     => [ '@id' => $home . '/#organization' ],
    // Enhanced for Google Rich Results
    'speakable' => [
        '@type' => 'SpeakableSpecification',
        'cssSelector' => ['.entry-content', '.post-content', '.article-content']
    ]
  ];

  // Add FAQ if page content exists
  $faq_items = [];
  if (!empty($page_content)) {
    // Extract questions and answers from content (simple implementation)
    $paragraphs = preg_split('/\n\s*\n/', $page_content);
    $question_count = 0;
    
    foreach ($paragraphs as $para) {
      $para = trim($para);
      if (strlen($para) > 50 && $question_count < 5) { // Simple filter for meaningful content
        $faq_items[] = [
          '@type' => 'Question',
          'name' => 'Tentang ' . $brand . ' - Bagian ' . ($question_count + 1),
          'acceptedAnswer' => [
            '@type' => 'Answer',
            'text' => wp_strip_all_tags(wp_trim_words($para, 50, ''))
          ]
        ];
        $question_count++;
      }
    }
    
    if (!empty($faq_items)) {
      $faq_node = [
        '@type' => 'FAQPage',
        '@id'   => $url . '#faq',
        'mainEntity' => $faq_items
      ];
      $graph = [$org_node, $breadcrumb, $webpage, $faq_node];
    } else {
      $graph = [$org_node, $breadcrumb, $webpage];
    }
  } else {
    $graph = [$org_node, $breadcrumb, $webpage];
  }

  $graph = ledak88_schema_force_types($graph); // ✅ FIX
  return $graph;
}

/** Build nodes untuk ContactPage (/kontak-kami) - Enhanced for Google Rich Results */
function ledak88_contact_graph_nodes(): array {
  $c     = ledak88_get_context();
  $home  = $c['brand_url'];        // no trailing slash
  $brand = $c['brand_name'];
  $url   = home_url('/kontak-kami/');
  
  // Extract contact information from page content
  $ci = ledak88_extract_contact_from_page();

  $breadcrumb = [
    '@type' => 'BreadcrumbList',
    '@id'   => $url . '#breadcrumb',
    'itemListElement' => [
      ['@type'=>'ListItem','position'=>1,'name'=>'Home','item'=>$home . '/'],
      ['@type'=>'ListItem','position'=>2,'name'=>'Kontak Kami','item'=>$url],
    ],
  ];

  // Get page content for description
  $page_id = get_page_by_path('kontak-kami');
  $page_description = 'Hubungi ' . $brand . ' untuk dukungan dan pertanyaan.';
  if ($page_id) {
    $page = get_post($page_id);
    if ($page && $page->post_excerpt) {
      $page_description = wp_strip_all_tags($page->post_excerpt);
    } elseif ($page && $page->post_content) {
      $page_description = wp_strip_all_tags(wp_trim_words($page->post_content, 30, ''));
    }
  }

  // Enhanced ContactPoint(s) for Google Rich Results
  $contactPoints = [];
  
  // Email contact point
  if (!empty($ci['emails'])) {
    $contactPoints[] = [
      '@type' => 'ContactPoint',
      'contactType' => 'customer service',
      'email' => $ci['emails'][0],
      'availableLanguage' => ['id','en'],
      'areaServed' => 'ID'
    ];
  }
  
  // Phone contact point
  if (!empty($ci['phones'])) {
    $contactPoints[] = [
      '@type' => 'ContactPoint',
      'contactType' => 'customer service',
      'telephone' => $ci['phones'][0],
      'availableLanguage' => ['id','en'],
      'areaServed' => 'ID'
    ];
  }
  
  // Default contact point if none from page
  if (empty($contactPoints)) {
    $contactPoints[] = [
      '@type' => 'ContactPoint',
      'contactType' => 'customer service',
      'availableLanguage' => ['id','en'],
      'areaServed' => 'ID'
    ];
  }

  // Build address array with structured data - postal code is optional
  $address_array = [
    '@type' => 'PostalAddress',
    'addressCountry' => 'ID'
  ];
  
  // Add street address if available
  if (!empty($ci['streetAddress'])) {
    $address_array['streetAddress'] = $ci['streetAddress'];
  } elseif (!empty($ci['address'])) {
    $address_array['streetAddress'] = $ci['address'];
  }
  
  // Add locality if available
  if (!empty($ci['addressLocality'])) {
    $address_array['addressLocality'] = $ci['addressLocality'];
  }
  
  // Add postal code if available (optional)
  if (!empty($ci['postalCode'])) {
    $address_array['postalCode'] = $ci['postalCode'];
  }

  // Enhanced Organization node with contact points
  $org_node = [
    '@type' => 'Organization',
    '@id'   => $home . '/#organization',
    'name' => $brand,
    'url' => $home . '/',
    'logo' => [
        '@type' => 'ImageObject',
        'url' => $c['logo_url'],
        'width' => $c['logo_width'],
        'height' => $c['logo_height'],
        'caption' => $brand . ' Logo'
    ],
    'description' => $brand . ' hadir sebagai platform hiburan digital dengan pendekatan informatif, transparan, dan ramah pengguna.',
    'sameAs' => [],
    'contactPoint' => $contactPoints,
    // Enhanced properties for Google Rich Results
    'foundingDate' => '2025',
    'founder' => [
        '@type' => 'Person',
        'name' => 'Tim ' . $brand
    ],
    'numberOfEmployees' => [
        '@type' => 'QuantitativeValue',
        'value' => '50'
    ],
    'address' => $address_array,
    'brand' => [
        '@type' => 'Brand',
        'name' => $brand
    ]
  ];

  // Enhanced ContactPage
  $webpage = [
    '@type' => ['WebPage','ContactPage'],
    '@id'   => $url . '#webpage',
    'url'   => $url,
    'name'  => 'Kontak ' . $brand,
    'isPartOf' => [ '@id' => $home . '/#website' ],
    'about'    => [ '@id' => $home . '/#organization' ],
    'primaryImageOfPage' => [ '@id' => $home . '/#primaryimage' ],
    'image'    => [ '@id' => $home . '/#primaryimage' ],
    'breadcrumb' => [ '@id' => $url . '#breadcrumb' ],
    'inLanguage'=> 'id-ID',
    'description' => $page_description,
    'headline'    => 'Kontak ' . $brand,
    'dateModified'=> $c['date_modified'],
    'mainEntityOfPage' => [ '@type' => 'WebPage', '@id' => $url ],
    'publisher'  => [ '@id' => $home . '/#organization' ],
    'author'     => [ '@id' => $home . '/#organization' ],
    // Enhanced for Google Rich Results
    'speakable' => [
        '@type' => 'SpeakableSpecification',
        'cssSelector' => ['.entry-content', '.post-content', '.article-content']
    ]
  ];

  // Additional ContactPoint Schema for better visibility
  $contact_schema = [
    '@type' => 'ContactPoint',
    'url' => $url,
    'contactType' => 'customer service',
    'availableLanguage' => 'Indonesian',
    'areaServed' => 'ID'
  ];
  
  if (!empty($ci['emails'])) {
    $contact_schema['email'] = $ci['emails'][0];
  }
  
  if (!empty($ci['phones'])) {
    $contact_schema['telephone'] = $ci['phones'][0];
  }

  $graph = [$org_node, $breadcrumb, $webpage, $contact_schema];
  $graph = ledak88_schema_force_types($graph); // ✅ FIX
  return $graph;
}

/* ---------------------------------------------------
 * Rank Math: buang node yang bentrok (hanya 2 page)
 * --------------------------------------------------- */
add_filter('rank_math/json_ld', function($data){
  if (!(is_page('tentang-kami') || is_page('kontak-kami'))) return $data;

  // tipe yang akan kita override di dua page ini
  $conflict = ['WebPage','BreadcrumbList','ContactPage','AboutPage','Organization','FAQPage','ContactPoint'];
  $filtered = [];
  foreach ((array)$data as $node) {
    if (!is_array($node)) { $filtered[] = $node; continue; }
    $types = $node['@type'] ?? null;
    $types = is_array($types) ? $types : ($types ? [$types] : []);
    if (!array_intersect($types, $conflict)) $filtered[] = $node;
  }
  return $filtered;
}, 10);