<?php
/*
Plugin Name: Geo Launch Pro
Description: Create geolocated landing pages from a base Elementor page. Uses Elementor’s Document API to clone layout exactly and regenerates CSS.
Version: 1.9.9
Author: App Monkeys LTD
*/

if ( ! function_exists( 'glp_fs' ) ) {
    /**
     * Freemius bootstrapping (loads early so the connect/activation flow can show).
     */
    function glp_fs() {
        global $glp_fs;

        if ( ! isset( $glp_fs ) ) {
            require_once dirname( __FILE__ ) . '/vendor/freemius/start.php';

            // Configure Freemius and nest its pages under our plugin's menu.
            $glp_fs = fs_dynamic_init( array(
                'id'                  => '21346',
                'slug'                => 'geo-launch-pro',
                'type'                => 'plugin',
                'public_key'          => 'pk_c1ac84557764f1975f02b41e99ea4',
                'is_premium'          => true,
                'has_premium_version' => true,
                'has_addons'          => false,
                'has_paid_plans'      => true,
                'menu'                => array(
                    // Use your existing dashboard as the entry.
                    'slug'       => 'geo-landing-pages',
                    'first-path' => 'admin.php?page=geo-landing-pages',
                    'support'    => false,
                    'contact'    => false,
                    // Make Freemius sub-pages appear under the same parent menu.
                    'parent'     => array( 'slug' => 'geo-landing-pages' ),
                ),
            ) );

            // Optional: if you want the connect popup on upgrade as well.
            $glp_fs->add_filter( 'show_trial', '__return_false' );
        }

        return $glp_fs;
    }

    // Initialize Freemius ASAP.
    glp_fs();
    do_action( 'glp_fs_loaded' );
}

/* ==============================
   Settings (kept from your code)
   ============================== */
add_action('admin_init', function () {
    // Legacy single options (kept for backward compatibility with older code)
    register_setting('geo_landing_pages_group', 'geo_base_page_id');
    register_setting('geo_landing_pages_group', 'geo_locations');
    register_setting('geo_landing_pages_group', 'geo_frequency');
    register_setting('geo_landing_pages_group', 'geo_pages_created');

    // NEW: multi-set option (array of page sets)
    register_setting('geo_landing_pages_group', 'geo_sets', [
        'type'              => 'array',
        'sanitize_callback' => 'geo_sanitize_geo_sets',
    ]);

    // Per-set runtime state: last run timestamps and completed locations
    register_setting('geo_landing_pages_group', 'geo_sets_state', [
        'type' => 'array'
    ]);

    // One-time migration from legacy fields.
    if (get_option('geo_sets_migrated') !== 'yes') {
        $base = get_option('geo_base_page_id', '');
        $locs = get_option('geo_locations', '');
        $freq = get_option('geo_frequency', 'daily');

        if ($base || $locs) {
            $sets = [[
                'id'           => 'set_' . wp_generate_uuid4(),
                'base_page_id' => intval($base),
                'frequency'    => in_array($freq, ['daily','weekly','twice_weekly','monthly'], true) ? $freq : 'daily',
                'locations'    => $locs,
            ]];
            update_option('geo_sets', $sets);
        } else {
            update_option('geo_sets', []);
        }

        update_option('geo_sets_state', []);
        update_option('geo_sets_migrated', 'yes');
    }
});

/**
 * Sanitize & mirror first set back to legacy options.
 */
function geo_sanitize_geo_sets($input) {
    if (!is_array($input)) return [];

    $out = [];
    foreach ($input as $set) {
        $out[] = [
            'id'           => isset($set['id']) && $set['id'] !== '' ? sanitize_text_field($set['id']) : 'set_' . wp_generate_uuid4(),
            'base_page_id' => isset($set['base_page_id']) ? intval($set['base_page_id']) : 0,
            'locations'    => isset($set['locations']) ? wp_kses_post($set['locations']) : '',
            'frequency'    => (isset($set['frequency']) && in_array($set['frequency'], ['daily','weekly','twice_weekly','monthly'], true))
                                ? $set['frequency'] : 'daily',
            'extra_footer_target_ids' => isset($set['extra_footer_target_ids']) ? sanitize_text_field($set['extra_footer_target_ids']) : '',
            'extra_footer_base_id'    => isset($set['extra_footer_base_id']) ? intval($set['extra_footer_base_id']) : 0,
        ];
    }

    if (!empty($out)) {
        update_option('geo_base_page_id', $out[0]['base_page_id']);
        update_option('geo_locations',    $out[0]['locations']);
        update_option('geo_frequency',    $out[0]['frequency']);
    }

    return $out;
}

/* ==============================
   Footer-links mapping refresh
   ============================== */
add_action('update_option_geo_sets', function ($old, $new) {
    $new_map = [];

    foreach ((array) $new as $set) {
        $base = isset($set['base_page_id']) ? (int) $set['base_page_id'] : 0;
        if (!$base) continue;

        $targets = [];
        if (!empty($set['extra_footer_target_ids'])) {
            foreach (preg_split('/[,\s]+/', $set['extra_footer_target_ids']) as $maybe) {
                $id = (int) $maybe;
                if ($id > 0) $targets[] = $id;
            }
        }
        $targets = array_values(array_unique($targets));
        $new_map[$base] = $targets;
    }

    $old_index = get_option('geo_footer_targets_index', []);
    if (!is_array($old_index)) $old_index = [];

    foreach ($old_index as $base => $old_targets) {
        $old_targets = (array) $old_targets;
        $new_targets = isset($new_map[$base]) ? (array) $new_map[$base] : [];
        $to_remove   = array_diff($old_targets, $new_targets);

        foreach ($to_remove as $pid) {
            $bases = get_post_meta($pid, '_geo_show_links_for_bases', true);
            if (!is_array($bases)) continue;

            $bases = array_map('intval', $bases);
            $bases = array_values(array_diff($bases, [(int) $base]));

            if (!empty($bases)) {
                update_post_meta($pid, '_geo_show_links_for_bases', $bases);
            } else {
                delete_post_meta($pid, '_geo_show_links_for_bases');
            }
        }
    }

    foreach ($new_map as $base => $targets) {
        foreach ((array) $targets as $pid) {
            $bases = get_post_meta($pid, '_geo_show_links_for_bases', true);
            if (!is_array($bases)) $bases = [];
            if (!in_array((int) $base, $bases, true)) {
                $bases[] = (int) $base;
                update_post_meta($pid, '_geo_show_links_for_bases', $bases);
            }
        }
    }

    update_option('geo_footer_targets_index', $new_map);
}, 10, 2);

/* ==============================
   Admin UI
   ============================== */
add_action('admin_menu', function () {
    add_menu_page(
        'Geo Launch Pro',
        'Geo Launch Pro',
        'manage_options',
        'geo-landing-pages',
        'geo_landing_pages_dashboard',
        'dashicons-location-alt',
        3
    );
});

/* =========================
   DASHBOARD
   ========================= */
function geo_landing_pages_dashboard() {
    if (!current_user_can('manage_options')) return;
    $tab = isset($_GET['tab']) ? sanitize_key($_GET['tab']) : 'config';

    echo '<div class="wrap geo-clean-admin">';
    echo '<h1>🌍 Geo Launch Pro</h1>';
    echo '<h2 class="nav-tab-wrapper">';
    echo '<a href="?page=geo-landing-pages&tab=config" class="nav-tab ' . ($tab === 'config' ? 'nav-tab-active' : '') . '">⚙ Configuration</a>';
    echo '<a href="?page=geo-landing-pages&tab=quickrun" class="nav-tab ' . ($tab === 'quickrun' ? 'nav-tab-active' : '') . '">⚡ Quick Run</a>';
    echo '<a href="?page=geo-landing-pages&tab=generated" class="nav-tab ' . ($tab === 'generated' ? 'nav-tab-active' : '') . '">📄 Generated Pages</a>';
    echo '</h2>';

    echo '<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">';
    echo '<style>
        .geo-clean-admin { font-family:"Poppins", sans-serif; }
        .geo-card { background:#fff; padding:20px; margin:20px 0; border-radius:10px; box-shadow:0 2px 5px rgba(0,0,0,0.08); }
        .geo-grid { display:grid; grid-template-columns:1fr 1fr; gap:20px; }
        .geo-card h3 { color:#0073aa; font-weight:600; margin-top:0; }
        input, textarea, select { width:100%; background:#f9f9f9; border:1px solid #ccc; border-radius:6px; padding:10px; font-size:14px; font-family:"Poppins", sans-serif; }
        input:focus, textarea:focus, select:focus { border-color:#A7E0FF; outline:none; box-shadow:0 0 0 2px rgba(167,224,255,0.3); }
        .button-primary { background:#A7E0FF; border:none; color:#111; font-weight:bold; border-radius:6px; padding:10px 20px; }
        .button-primary:hover { background:#7ccfff; }
        .nav-tab-wrapper { margin-top:20px; }
        .nav-tab { border-radius:6px 6px 0 0; }
        .link-delete { color:#b32d2e; }
        .geo-table td, .geo-table th { vertical-align: top; }
    </style>';

    if ($tab === 'config') {
        $sets = get_option('geo_sets', []);
        if (!is_array($sets)) { $sets = []; }

        echo '<form method="post" action="options.php">';
        settings_fields('geo_landing_pages_group');
        do_settings_sections('geo_landing_pages_group');

        echo '<div id="geo-sets-container">';

        if (empty($sets)) {
            $sets = [[
                'id'           => 'set_' . wp_generate_uuid4(),
                'base_page_id' => '',
                'frequency'    => 'daily',
                'locations'    => '',
            ]];
        }

        $index = 0;
        foreach ($sets as $set) {
            $sid   = isset($set['id'])           ? $set['id']           : 'set_' . wp_generate_uuid4();
            $base  = isset($set['base_page_id']) ? intval($set['base_page_id']) : '';
            $freq  = isset($set['frequency'])    ? $set['frequency']    : 'daily';
            $locs  = isset($set['locations'])    ? $set['locations']    : '';

            echo '<div class="geo-set" style="margin-bottom:24px;">';
            echo '<div class="geo-grid">';

            echo '<div class="geo-card">';
            echo '<h3>Base Settings</h3>';
            echo '<input type="hidden" name="geo_sets['.$index.'][id]" value="'.esc_attr($sid).'">';
            echo '<p><label>Base Page ID<br>
                    <input type="number" name="geo_sets['.$index.'][base_page_id]" value="'.esc_attr($base).'">
                  </label></p>';

            $plan = geo_get_current_plan();
            echo '<p><label>Frequency<br><select name="geo_sets['.$index.'][frequency]">';
            if ($plan === 'free') {
                echo '<option value="weekly" '.selected($freq, 'weekly', false).'>Weekly</option>';
            } else {
                echo '<option value="daily" '.selected($freq, 'daily', false).'>Daily</option>';
                echo '<option value="weekly" '.selected($freq, 'weekly', false).'>Weekly</option>';
                echo '<option value="twice_weekly" '.selected($freq, 'twice_weekly', false).'>Twice Weekly</option>';
                echo '<option value="monthly" '.selected($freq, 'monthly', false).'>Monthly</option>';
            }
            echo '</select></label></p>';
            echo '</div>';

            echo '<div class="geo-card">';
            echo '<h3>Drip-feed Locations</h3>';
            echo '<p><textarea name="geo_sets['.$index.'][locations]" rows="10" placeholder="One per line or comma separated">'
                 .esc_textarea($locs).'</textarea></p>';
            echo '</div>';

            echo '</div>'; // .geo-grid

            $extra_target_ids = isset($set['extra_footer_target_ids']) ? $set['extra_footer_target_ids'] : '';
            $extra_base_id    = isset($set['extra_footer_base_id'])    ? (int) $set['extra_footer_base_id'] : 0;

            echo '<div class="geo-card" style="grid-column:1 / -1; margin-top:10px;">';
            echo '<h3>Footer link options</h3>';

            echo '<p><label>Also show links on page ID<br>
                    <input type="text"
                           name="geo_sets['.$index.'][extra_footer_target_ids]"
                           value="'.esc_attr($extra_target_ids).'"
                           placeholder="Optional page ID(s), comma separated">
                  </label></p>';
            echo '<p class="description">If set, the list of generated location pages will also appear in the footer of these page(s).</p>';

            echo '<p><label>Use links from base page ID<br>
                    <input type="number"
                           name="geo_sets['.$index.'][extra_footer_base_id]"
                           value="'.esc_attr($extra_base_id).'"
                           placeholder="Optional base page ID">
                  </label></p>';
            echo '<p class="description">Leave empty to use this set’s Base Page ID. Set this if you want the footer list to come from a different base page.</p>';
            echo '</div>';

            echo '<p><a href="#" class="button link-delete geo-remove-set">Remove this page set</a></p>';
            echo '<hr style="border:none;height:1px;background:#e7e7e7;margin:20px 0;">';
            echo '</div>';

            $index++;
        }

        echo '</div>';
        echo '<p><a href="#" id="geo-add-set" class="button button-secondary">+ Add another page</a></p>';
        submit_button('💾 Save Settings');
        echo '</form>';

        ?>
        <script type="text/template" id="geo-set-template">
            <div class="geo-set" style="margin-bottom:24px;">
                <div class="geo-grid">
                    <div class="geo-card">
                        <h3>Base Settings</h3>
                        <input type="hidden" name="geo_sets[__INDEX__][id]" value="set_<?php echo esc_js( wp_generate_uuid4() ); ?>">
                        <p><label>Base Page ID<br>
                            <input type="number" name="geo_sets[__INDEX__][base_page_id]" value="">
                        </label></p>
                        <p><label>Frequency<br>
                            <select name="geo_sets[__INDEX__][frequency]">
                                <option value="daily">Daily</option>
                                <option value="weekly">Weekly</option>
                                <option value="twice_weekly">Twice Weekly</option>
                                <option value="monthly">Monthly</option>
                            </select>
                        </label></p>
                    </div>
                    <div class="geo-card">
                        <h3>Drip-feed Locations</h3>
                        <p><textarea name="geo_sets[__INDEX__][locations]" rows="10" placeholder="One per line or comma separated"></textarea></p>
                    </div>
                </div>

                <div class="geo-card" style="grid-column:1 / -1; margin-top:10px;">
                    <h3>Footer link options</h3>

                    <p><label>Also show links on page ID<br>
                        <input type="text"
                               name="geo_sets[__INDEX__][extra_footer_target_ids]"
                               value=""
                               placeholder="Optional page ID(s), comma separated">
                    </label></p>
                    <p class="description">If set, the list of generated location pages will also appear in the footer of these page(s).</p>

                    <p><label>Use links from base page ID<br>
                        <input type="number"
                               name="geo_sets[__INDEX__][extra_footer_base_id]"
                               value=""
                               placeholder="Optional base page ID">
                    </label></p>
                    <p class="description">Leave empty to use this set’s Base Page ID. Set this if you want the footer list to come from a different base page.</p>
                </div>

                <p><a href="#" class="button link-delete geo-remove-set">Remove this page set</a></p>
                <hr style="border:none;height:1px;background:#e7e7e7;margin:20px 0;">
            </div>
        </script>
        <script>
        (function(){
            var nextIndex = <?php echo (int)$index; ?>;
            var container = document.getElementById('geo-sets-container');
            var addBtn    = document.getElementById('geo-add-set');

            if (addBtn) {
                addBtn.addEventListener('click', function(e){
                    e.preventDefault();
                    var tpl = document.getElementById('geo-set-template').innerHTML;
                    tpl = tpl.replace(/__INDEX__/g, nextIndex);
                    container.insertAdjacentHTML('beforeend', tpl);
                    nextIndex++;
                });
            }

            document.addEventListener('click', function(e){
                if (e.target && e.target.classList.contains('geo-remove-set')) {
                    e.preventDefault();
                    var wrap = e.target.closest('.geo-set');
                    if (wrap) wrap.remove();
                }
            });
        })();
        </script>
        <?php

    } elseif ($tab === 'quickrun') {
        $plan = geo_get_current_plan();

        echo '<div class="geo-card">';
        echo '<h3>📋 Your Plan: ' . ucfirst($plan) . '</h3>';

        if ($plan === 'free') {
            echo '<p>You are on the <strong>Free Plan</strong>. Quick Run isn’t available. You can create <strong>1 page per week</strong> via drip-feed. ';
            echo '<a href="' . esc_url( glp_fs()->get_upgrade_url() ) . '">Upgrade</a> for more features.</p>';
        } elseif ($plan === 'monthly') {
            echo '<p>You are on the <strong>Monthly Plan</strong>. Quick Run is not included. ';
            echo '<a href="' . esc_url( glp_fs()->get_upgrade_url() ) . '">Upgrade to Yearly</a> to enable Quick Run.</p>';
        } else {
            echo '<p>You are on the <strong>Yearly Plan</strong>. You have full access to Quick Run and drip-feed features.</p>';
        }
        echo '</div>';

        if ($plan !== 'yearly') {
            if (!empty($_GET['limit'])) {
                echo '<div class="geo-card"><h3>🚫 Limit Reached</h3>
                      <p>On the Free plan you can only generate 1 page per week.</p></div>';
            }
        } else {
            if (!empty($_GET['done'])) {
                $sum = get_transient('geo_last_quickrun_summary');
                echo '<div class="geo-card"><h3>✅ Quick Run Complete</h3>';
                if ($sum && !empty($sum['created'])) {
                    echo '<ul>';
                    foreach ($sum['created'] as $row) {
                        echo '<li><a href="' . esc_url($row['view']) . '" target="_blank">' . esc_html($row['title']) . '</a> 
                              • <a href="' . esc_url($row['edit']) . '" target="_blank">Edit</a> 
                              • ID: ' . (int)$row['id'] . '</li>';
                    }
                    echo '</ul>';
                } else {
                    echo '<p>No new pages created.</p>';
                }
                echo '</div>';
            }

            $saved_base = intval(get_option('geo_base_page_id'));

            echo '<div class="geo-card">';
            echo '<h3>⚡ Quick Run</h3>';
            echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '">';

            echo '<p><label>Base Page ID (optional override)<br>';
            echo '<input type="number" name="base_page_id" value="" placeholder="' . esc_attr($saved_base ?: 'Enter base page id') . '"></label></p>';
            if ($saved_base) {
                echo '<p><em>Saved Base Page ID is <strong>' . $saved_base . '</strong>. Leave the field empty to use this.</em></p>';
            } else {
                echo '<p><em>No saved Base Page ID yet. You can enter one here.</em></p>';
            }

            echo '<p><label>Locations (comma or one per line)<br>';
            echo '<textarea name="quickrun_locations" rows="6" placeholder="Shrewsbury&#10;Telford"></textarea></label></p>';
            echo '<p style="color:#b32d2e;font-weight:600;">A maximum of 15 locations can be entered per Quick Run. If you enter more than 15 the first 15 will be used.</p>';

            echo '<p><label>
                    <input type="checkbox" name="qr_extra_footer_on_base" value="1">
                    Also show links on the base page
                  </label></p>';

            echo '<p><label>Also show links on these page IDs <small>comma separated</small><br>
                    <input type="text" name="qr_extra_footer_target_ids" placeholder="e.g. 12,34,56">
                  </label></p>';

            wp_nonce_field('geo_quick_run');
            echo '<input type="hidden" name="action" value="geo_quick_run">';

            submit_button('🚀 Generate Pages Now');
            echo '</form>';

            echo '<div id="geo-overlay" style="display:none;position:fixed;top:0;left:0;right:0;bottom:0;
                    background:rgba(255,255,255,0.85);z-index:9999;align-items:center;justify-content:center;
                    font-family:Poppins,sans-serif;font-size:18px;color:#333;">
                    <div>🚀 Generating pages, please wait...</div>
                  </div>';

            echo '<script>
                (function(){
                    var form = document.querySelector(".geo-card form");
                    var overlay = document.getElementById("geo-overlay");
                    if(form && overlay){
                        form.addEventListener("submit", function(){
                            overlay.style.display = "flex";
                        });
                    }
                })();
            </script>';

            echo '</div>';
        }

    } elseif ($tab === 'generated') {
        $plan = geo_get_current_plan();

        echo '<div class="geo-card">';
        echo '<h3>📋 Your Plan: ' . ucfirst($plan) . '</h3>';
        if ($plan === 'free') {
            echo '<p>You are on the <strong>Free Plan</strong>. You can only generate <strong>1 page per week</strong>. ';
            echo '<a href="' . esc_url( glp_fs()->get_upgrade_url() ) . '">Upgrade</a> for more.</p>';
        } elseif ($plan === 'monthly') {
            echo '<p>You are on the <strong>Monthly Plan</strong>. Full drip-feed access, Quick Run not included. ';
            echo '<a href="' . esc_url( glp_fs()->get_upgrade_url() ) . '">Upgrade to Yearly</a>.</p>';
        } else {
            echo '<p>You are on the <strong>Yearly Plan</strong>. Full access to everything.</p>';
        }
        echo '</div>';

        $q = new WP_Query([
            'post_type'      => 'page',
            'post_status'    => 'publish',
            'posts_per_page' => -1,
            'meta_query'     => [
                [
                    'key'     => '_geo_generated_from',
                    'compare' => 'EXISTS',
                ],
            ],
            'orderby'        => 'date',
            'order'          => 'DESC',
        ]);

        echo '<div class="geo-card"><h3>📄 Generated Pages</h3>';

        if ($q->have_posts()) {
            echo '<table class="widefat striped geo-table"><thead><tr>
                    <th>Title</th><th>ID</th><th>Base Page</th><th>Date</th><th>Links</th><th>Action</th>
                  </tr></thead><tbody>';
            while ($q->have_posts()) { $q->the_post();
                $pid     = get_the_ID();
                $base_id = intval( get_post_meta($pid, '_geo_generated_from', true) );
                $del_url = wp_nonce_url(
                    admin_url('admin-post.php?action=geo_delete_page&id=' . $pid),
                    'geo_delete_' . $pid
                );
                echo '<tr>
                        <td>' . esc_html(get_the_title()) . '</td>
                        <td>' . $pid . '</td>
                        <td>' . ($base_id ? ('<a href="'.esc_url(get_edit_post_link($base_id)).'">#'.$base_id.'</a>') : '-') . '</td>
                        <td>' . esc_html(get_the_date()) . '</td>
                        <td><a href="' . esc_url(get_permalink($pid)) . '" target="_blank">View</a> • <a href="' . esc_url(get_edit_post_link($pid)) . '">Edit</a></td>
                        <td><a href="' . esc_url($del_url) . '" class="button button-small button-danger" onclick="return confirm(\'Delete this page?\');">Delete</a></td>
                      </tr>';
            }
            wp_reset_postdata();
            echo '</tbody></table>';
        } else {
            echo '<p>No generated pages found.</p>';
        }

        echo '</div>';
    }

    echo '</div>'; // .wrap
}

/* ==============================
   Helpers
   ============================== */
function geo_parse_locations_string($raw) {
    $parts = preg_split('/[\r\n,]+/', (string)$raw);
    $parts = array_map('trim', $parts);
    $parts = array_filter($parts, function($v) { return $v !== ''; });
    $parts = array_unique($parts);
    return array_values($parts);
}

function geo_frequency_interval_seconds($freq) {
    switch ($freq) {
        case 'daily':         return 60*60*24;
        case 'weekly':        return 60*60*24*7;
        case 'twice_weekly':  return 60*60*24*3.5;
        case 'monthly':       return 60*60*24*30;
        default:              return 60*60*24*7;
    }
}

function geo_log_page_creation($new_id) {
    $log = get_option('geo_drip_usage_log', []);
    if (!is_array($log)) $log = [];
    $log[] = ['page_id' => (int) $new_id, 'time' => time()];
    update_option('geo_drip_usage_log', $log, false);
}

/**
 * 🔑 Map Freemius plan → our internal label.
 * Uses plan **unique names**: dripfeedpro (monthly), quickrunpro (yearly).
 */
function geo_get_current_plan() {
    if ( function_exists('glp_fs') ) {
        $fs = glp_fs();

        if ( $fs->is_registered() ) {
            if ( $fs->is_plan( 'quickrunpro' ) ) {
                return 'yearly';
            }
            if ( $fs->is_plan( 'dripfeedpro' ) ) {
                return 'monthly';
            }
            return 'free';
        }
    }
    return 'free';
}

function geo_recursive_token_replace($value, $location) {
    if (is_string($value))  return str_replace('{{location}}', $location, $value);
    if (is_array($value))   { foreach ($value as $k => $v) { $value[$k] = geo_recursive_token_replace($v, $location); } return $value; }
    if (is_object($value))  { foreach ($value as $k => $v) { $value->$k = geo_recursive_token_replace($v, $location); } return $value; }
    return $value;
}

function geo_copy_meta_and_terms($base_id, $new_id, $location) {
    $skip = [
        '_elementor_data','_elementor_edit_mode','_elementor_template_type',
        '_elementor_version','_elementor_css','_elementor_css_meta',
        '_elementor_page_assets','_edit_lock','_edit_last','_wp_old_slug',
        '_wp_page_template','_thumbnail_id','_geo_generated_from',
    ];
    $all_meta = get_post_meta($base_id);
    if (is_array($all_meta)) {
        foreach ($all_meta as $key => $vals) {
            if (in_array($key, $skip, true)) continue;
            foreach ((array)$vals as $raw) {
                $val = maybe_unserialize($raw);
                $val = geo_recursive_token_replace($val, $location);
                add_post_meta($new_id, $key, $val);
            }
        }
    }
    $taxes = get_object_taxonomies('page');
    foreach ($taxes as $tax) {
        $term_ids = wp_get_object_terms($base_id, $tax, ['fields' => 'ids']);
        if (!is_wp_error($term_ids) && !empty($term_ids)) {
            wp_set_object_terms($new_id, $term_ids, $tax, false);
        }
    }
}

/* ==============================
   Elementor duplication
   ============================== */
function geo_duplicate_elementor_page_exact($base_id, $location) {
    $base = get_post($base_id);
    if (!$base || $base->post_type !== 'page') {
        return new WP_Error('base_missing', 'Base page missing');
    }

    $data_raw = get_post_meta($base_id, '_elementor_data', true);
    if (empty($data_raw)) {
        return new WP_Error('no_elementor', 'Base page has no Elementor data');
    }

    $slug_base = $base->post_name ? $base->post_name : sanitize_title($base->post_title);
    $slug_base = preg_replace('/-\d+$/', '', $slug_base);
    $slug = sanitize_title($slug_base . ' ' . $location);

    if (get_page_by_path($slug, OBJECT, 'page')) {
        return new WP_Error('exists', 'Page already exists for ' . $location);
    }

    $new_id = wp_insert_post([
        'post_title'   => $base->post_title . ' ' . $location,
        'post_name'    => $slug,
        'post_status'  => 'publish',
        'post_type'    => 'page',
        'post_parent'  => $base->post_parent,
        'menu_order'   => $base->menu_order,
        'post_excerpt' => $base->post_excerpt,
    ]);
    if (is_wp_error($new_id) || !$new_id) {
        return new WP_Error('insert_failed', is_wp_error($new_id) ? $new_id->get_error_message() : 'Insert failed');
    }

    $template = get_post_meta($base_id, '_wp_page_template', true);
    if ($template) update_post_meta($new_id, '_wp_page_template', $template);
    $thumb_id = get_post_thumbnail_id($base_id);
    if ($thumb_id) set_post_thumbnail($new_id, $thumb_id);

    update_post_meta($new_id, '_elementor_edit_mode', 'builder');
    update_post_meta($new_id, '_elementor_template_type', 'wp-page');
    if (defined('ELEMENTOR_VERSION')) update_post_meta($new_id, '_elementor_version', ELEMENTOR_VERSION);

    $data_raw_for_new = str_replace('{{location}}', $location, $data_raw);

    $saved_via_document = false;
    if (class_exists('\Elementor\Plugin')) {
        try {
            $data_arr = json_decode($data_raw_for_new, true);
            if (is_array($data_arr)) {
                $doc = \Elementor\Plugin::$instance->documents->get($new_id);
                if ($doc) {
                    $doc->save(['elements' => $data_arr, 'settings' => []]);
                    $saved_via_document = true;
                }
            }
        } catch (\Throwable $e) {
            error_log('Geo Launch Pro: Elementor doc save failed - ' . $e->getMessage());
        }
    }
    if (!$saved_via_document) {
        update_post_meta($new_id, '_elementor_data', $data_raw_for_new);
    }

    if (!empty($base->post_content)) {
        wp_update_post([
            'ID'           => $new_id,
            'post_content' => str_replace('{{location}}', $location, $base->post_content),
        ]);
    }

    geo_copy_meta_and_terms($base_id, $new_id, $location);
    update_post_meta($new_id, '_geo_generated_from', $base_id);

    if (class_exists('\Elementor\Core\Files\CSS\Post')) {
        try { $css = \Elementor\Core\Files\CSS\Post::create($new_id); $css->update(); } catch (\Throwable $e) {}
    } elseif (class_exists('\Elementor\Plugin')) {
        try { \Elementor\Plugin::$instance->files_manager->clear_cache(); } catch (\Throwable $e) {}
    }

    return $new_id;
}

/* ==============================
   Batch creator
   ============================== */
function geo_create_pages_from_locations($locations, $base_id = null) {
    if (!$base_id) $base_id = intval(get_option('geo_base_page_id'));
    $created = [];
    foreach ($locations as $loc) {
        $new = geo_duplicate_elementor_page_exact($base_id, $loc);
        if (!is_wp_error($new)) {
            $created[] = [
                'id'    => $new,
                'title' => get_the_title($new),
                'view'  => get_permalink($new),
                'edit'  => get_edit_post_link($new, ''),
            ];
            geo_log_page_creation($new);
        }
    }
    return $created;
}

/* ==============================
   Quick Run handler (Yearly only)
   ============================== */
add_action('admin_post_geo_quick_run', function () {
    if (!current_user_can('manage_options')) wp_die('Access denied');
    check_admin_referer('geo_quick_run');

    if (geo_get_current_plan() !== 'yearly') {
        wp_redirect( admin_url('admin.php?page=geo-landing-pages&tab=quickrun&forbidden=1') );
        exit;
    }

    $raw  = isset($_POST['quickrun_locations']) ? wp_unslash($_POST['quickrun_locations']) : '';
    $base = isset($_POST['base_page_id']) ? intval($_POST['base_page_id']) : 0;
    if (!$base) $base = intval(get_option('geo_base_page_id'));

    $locations = geo_parse_locations_string($raw);
    if (count($locations) > 15) $locations = array_slice($locations, 0, 15);

    if (!$base || empty($locations)) {
        wp_redirect( admin_url('admin.php?page=geo-landing-pages&tab=quickrun&done=0') );
        exit;
    }

    $created = geo_create_pages_from_locations($locations, $base);

    $targets_raw = isset($_POST['qr_extra_footer_target_ids']) ? sanitize_text_field($_POST['qr_extra_footer_target_ids']) : '';
    $on_base     = ! empty($_POST['qr_extra_footer_on_base']);
    $targets     = [];

    if ($on_base && $base) $targets[] = (int) $base;
    if ($targets_raw) {
        foreach (preg_split('/[,\s]+/', $targets_raw) as $maybe) {
            $id = (int) $maybe; if ($id > 0) $targets[] = $id;
        }
    }
    $targets = array_values(array_unique($targets));

    foreach ($targets as $page_id) {
        $bases = get_post_meta($page_id, '_geo_show_links_for_bases', true);
        if (!is_array($bases)) $bases = [];
        if (!in_array($base, $bases, true)) {
            $bases[] = (int) $base;
            update_post_meta($page_id, '_geo_show_links_for_bases', $bases);
        }
    }

    set_transient('geo_last_quickrun_summary', ['created' => $created], 600);
    wp_redirect( admin_url('admin.php?page=geo-landing-pages&tab=quickrun&done=1') );
    exit;
});

/* ==============================
   Cron drip feed for ALL sets
   ============================== */
add_action('init', function () {
    if (!wp_next_scheduled('geo_landing_pages_cron')) {
        wp_schedule_event(time() + 1200, 'daily', 'geo_landing_pages_cron');
    }
});

function geo_can_free_create() {
    $log = get_option('geo_drip_usage_log', []);
    if (!is_array($log)) return true;
    $start_of_week = strtotime('monday this week');
    foreach ($log as $entry) {
        if (isset($entry['time']) && $entry['time'] >= $start_of_week) return false;
    }
    return true;
}

add_action('geo_landing_pages_cron', function () {
    $sets  = get_option('geo_sets', []);
    $state = get_option('geo_sets_state', []);
    if (!is_array($state)) $state = [];

    if (is_array($sets) && !empty($sets)) {
        foreach ($sets as $set) {
            $sid   = $set['id'];
            $base  = intval($set['base_page_id']);
            $freq  = $set['frequency'];
            $locs  = geo_parse_locations_string($set['locations']);
            if (!$base || empty($locs)) continue;

            if (!isset($state[$sid])) $state[$sid] = ['last_run' => 0, 'done' => []];

            $now      = time();
            $interval = geo_frequency_interval_seconds($freq);
            $elapsed  = $now - intval($state[$sid]['last_run']);
            if ($elapsed < $interval) continue;

            $plan = geo_get_current_plan();
            if ($plan === 'free' && !geo_can_free_create()) continue;

            $done = is_array($state[$sid]['done']) ? $state[$sid]['done'] : [];
            $next = null;
            foreach ($locs as $loc) { if (!in_array($loc, $done, true)) { $next = $loc; break; } }
            if (!$next) { $state[$sid]['last_run'] = $now; continue; }

            $created = geo_create_pages_from_locations([$next], $base);
            if (!empty($created)) {
                $done[] = $next;
                $state[$sid]['done']     = array_values(array_unique($done));
                $state[$sid]['last_run'] = $now;
            }
        }
        update_option('geo_sets_state', $state);
    } else {
        $pool = geo_parse_locations_string(get_option('geo_locations', ''));
        $done = get_option('geo_pages_created', []);
        if (!is_array($done)) $done = [];

        foreach ($pool as $loc) {
            if (geo_get_current_plan() === 'free' && !geo_can_free_create()) break;
            if (in_array($loc, $done, true)) continue;
            $new = geo_create_pages_from_locations([$loc]);
            if (!empty($new)) {
                $done[] = $loc;
                update_option('geo_pages_created', $done);
            }
            break;
        }
    }
});

/* ==============================
   Pages list: show Page ID
   ============================== */
add_filter('manage_pages_columns', function ($cols) { $cols['page_id'] = 'Page ID'; return $cols; });
add_action('manage_pages_custom_column', function ($col, $id) { if ($col === 'page_id') echo (int)$id; }, 10, 2);
add_filter('manage_edit-page_sortable_columns', function ($cols) { $cols['page_id'] = 'ID'; return $cols; });

/* ==============================
   Footer links on relevant pages
   ============================== */
add_action('wp_footer', function () {
    if (is_admin()) return;
    global $post; if (!$post) return;

    $base_ids = [];
    $from = (int) get_post_meta($post->ID, '_geo_generated_from', true);
    if ($from > 0) $base_ids[] = $from;

    $attached = get_post_meta($post->ID, '_geo_show_links_for_bases', true);
    if (is_array($attached)) { foreach ($attached as $bid) { $bid = (int) $bid; if ($bid > 0) $base_ids[] = $bid; } }

    $base_ids = array_values(array_unique($base_ids));
    if (empty($base_ids)) return;

    $meta_query = ['relation' => 'OR'];
    foreach ($base_ids as $bid) {
        $meta_query[] = ['key' => '_geo_generated_from', 'value' => $bid, 'compare' => '='];
    }

    $pages = get_posts([
        'post_type'   => 'page',
        'post_status' => 'publish',
        'numberposts' => -1,
        'orderby'     => 'title',
        'order'       => 'ASC',
        'meta_query'  => $meta_query,
        'fields'      => 'all',
    ]);
    if (!$pages) return;

    $seen = []; $output = [];
    foreach ($pages as $p) {
        if ($p->ID === $post->ID) continue;
        if (isset($seen[$p->ID])) continue;
        $seen[$p->ID] = true; $output[] = $p;
    }
    if (empty($output)) return;

    echo '<div class="geo-footer-links"><nav aria-label="Locations"><ul class="geo-footer-locations">';
    foreach ($output as $p) echo '<li><a href="' . esc_url(get_permalink($p->ID)) . '">' . esc_html(get_the_title($p->ID)) . '</a></li>';
    echo '</ul></nav></div>';
    echo '<style>.geo-footer-locations{display:flex;flex-wrap:wrap;gap:.5em 1em;list-style:none;margin:0;padding:0}.geo-footer-locations li{margin:0}</style>';
});

/* ==============================
   Delete generated page handler
   ============================== */
add_action('admin_post_geo_delete_page', function () {
    if (!current_user_can('manage_options')) wp_die('Access denied');
    $id = isset($_GET['id']) ? intval($_GET['id']) : 0;
    if (!$id) wp_die('No page ID provided');
    check_admin_referer('geo_delete_' . $id);
    wp_delete_post($id, true);
    wp_redirect(admin_url('admin.php?page=geo-landing-pages&tab=generated&deleted=1'));
    exit;
});
