<?php

/**
 * AP Family Archive - Activator
 *
 * This plugin owns NO data tables in 0.1.0 (display/config live in options;
 * apfaar_* tables get minted only when a feature needs one - spec-02 Section 2).
 * ALL genealogical data belongs to the ANCP Core Library (Schema); this
 * activator delegates schema creation to the core and never defines core
 * schema itself. Safe to call on both fresh installs and upgrades.
 *
 * CO-EXISTENCE GUARD (standalone install): the shared core renames the legacy
 * apft_ core tables to ancp_ on first adoption (spec-00 Section 9). If this
 * plugin is activated on a site still running the OLD, un-adopted AP Family
 * Trees (its live data in apft_ tables), running that rename would rip the
 * tables out from under Trees. So before any migration we detect that state
 * and abort safely, leaving every table untouched and asking the owner to
 * update AP Family Trees to its core-adoption release first.
 *
 * @package    APFAAR_Family_Archive
 * @subpackage APFAAR_Family_Archive/includes
 * @since      0.1.0
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
/**
 * Activation routines.
 *
 * @since 0.1.0
 */
class APFAAR_Activator {
    /**
     * Option flag set when the co-existence guard has blocked the migration.
     * Its presence drives the admin notice; it is cleared the moment the
     * blocking condition clears (Trees updated to the core-adoption release).
     *
     * @var string
     */
    const COEXIST_OPTION = 'apfaar_coexist_block';

    /**
     * Create/upgrade tables and stamp versions.
     *
     * @return void
     */
    public static function activate() {
        $proceeded = self::create_tables();
        update_option( 'apfaar_version', APFAAR_VERSION );
        if ( !get_option( 'apfaar_activation_time' ) ) {
            update_option( 'apfaar_activation_time', time() );
        }
        // Only stamp the DB version once the schema actually ran. When the
        // co-existence guard blocked it, leaving this unstamped keeps the
        // self-heal check re-trying on every admin load until Trees updates.
        if ( $proceeded ) {
            update_option( 'apfaar_db_version', APFAAR_VERSION );
        }
    }

    /**
     * Ensure the shared core schema exists and is current.
     *
     * Core tables (trees, people, families, events, ...) are created by the
     * ANCP Core Library. Called from the plugins_loaded self-heal check as
     * well as activation, so the core boot is guarded rather than assumed.
     * (Same pattern as AP Family Trees / AP One-Name Studies.)
     *
     * @return bool True if the migration + schema install ran; false if the
     *              co-existence guard blocked it.
     */
    public static function create_tables() {
        // Ensure the core is booted, then let it own the core-table schema.
        if ( class_exists( 'AncestorPress\\Core\\Loader' ) && !\AncestorPress\Core\Loader::is_booted() ) {
            \AncestorPress\Core\Loader::boot();
        }
        // Co-existence guard: never migrate/clobber an old, un-adopted AP
        // Family Trees still on the legacy apft_ tables (see the class header).
        if ( self::old_family_trees_present() ) {
            update_option( self::COEXIST_OPTION, 1 );
            return false;
        }
        delete_option( self::COEXIST_OPTION );
        // Run the apft_ -> ancp_ prefix migration first (guarded, idempotent,
        // abort-safe) so the schema install targets the correct names. On an
        // Archive-first install this is a no-op that stamps the ancp_ prefix.
        if ( class_exists( 'AncestorPress\\Core\\Migrator' ) ) {
            \AncestorPress\Core\Migrator::maybe_migrate();
        }
        if ( class_exists( 'AncestorPress\\Core\\Schema' ) ) {
            \AncestorPress\Core\Schema::install();
        }
        return true;
    }

    // ── Co-existence detection ────────────────────────────────────────────────
    /**
     * Whether an old, un-adopted AP Family Trees is present and would be
     * clobbered by the core prefix migration.
     *
     * Gathers the live signals and applies the pure decision below; the result
     * passes through a filter so a site owner or test can override it.
     *
     * @return bool
     */
    public static function old_family_trees_present() {
        $on_core = class_exists( 'AncestorPress\\Core\\Table_Map' ) && \AncestorPress\Core\Table_Map::TARGET_PREFIX === \AncestorPress\Core\Table_Map::active_prefix();
        $blocked = self::coexistence_blocked(
            self::family_trees_active(),
            $on_core,
            self::core_people_table_exists( self::legacy_prefix() ),
            self::core_people_table_exists( self::target_prefix() )
        );
        /**
         * Filter the AP Family Trees co-existence decision (also a test seam).
         *
         * @since 0.1.0
         * @param bool $blocked True to block the core migration.
         */
        return (bool) apply_filters( 'apfaar_coexistence_block', $blocked );
    }

    /**
     * The pure decision: block the migration only when AP Family Trees is
     * present, the shared core has NOT been adopted yet, and its legacy
     * apft_ core data is live (present) with no ancp_ core tables to move to.
     *
     * @param  bool $trees_active AP Family Trees is active.
     * @param  bool $on_core      The shared core prefix is already ancp_.
     * @param  bool $has_legacy   A legacy apft_ core table exists.
     * @param  bool $has_target   The ancp_ core table already exists.
     * @return bool
     */
    public static function coexistence_blocked(
        $trees_active,
        $on_core,
        $has_legacy,
        $has_target
    ) {
        if ( !$trees_active ) {
            return false;
            // Trees absent -> any apft_ tables are orphaned; safe to adopt.
        }
        if ( $on_core ) {
            return false;
            // Already on the shared core -> nothing to protect.
        }
        return $has_legacy && !$has_target;
        // Old Trees on apft_, not yet migrated.
    }

    /**
     * Whether AP Family Trees is active on this site.
     *
     * @return bool
     */
    private static function family_trees_active() {
        if ( !function_exists( 'is_plugin_active' ) ) {
            require_once ABSPATH . 'wp-admin/includes/plugin.php';
        }
        if ( is_plugin_active( 'ap-family-trees/ap-family-trees.php' ) ) {
            return true;
        }
        // Fallback: Trees loaded under a non-standard folder name still defines
        // these markers.
        return defined( 'APFT_VERSION' ) || function_exists( 'apft_fs' );
    }

    /**
     * Whether the core `people` table exists under a given prefix.
     *
     * @param  string $prefix Core prefix (apft_ or ancp_).
     * @return bool
     */
    private static function core_people_table_exists( $prefix ) {
        global $wpdb;
        $name = $wpdb->prefix . $prefix . 'people';
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- one-off schema probe at activation; caching would mask reality.
        return (bool) $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $name ) );
    }

    /**
     * Legacy core prefix (from the core map when booted, else the constant).
     *
     * @return string
     */
    private static function legacy_prefix() {
        return ( class_exists( 'AncestorPress\\Core\\Table_Map' ) ? \AncestorPress\Core\Table_Map::LEGACY_PREFIX : 'apft_' );
    }

    /**
     * Target core prefix (from the core map when booted, else the constant).
     *
     * @return string
     */
    private static function target_prefix() {
        return ( class_exists( 'AncestorPress\\Core\\Table_Map' ) ? \AncestorPress\Core\Table_Map::TARGET_PREFIX : 'ancp_' );
    }

    /**
     * Admin notice shown while the co-existence guard is blocking (hooked on
     * admin_notices from the main plugin file).
     *
     * @return void
     */
    public static function render_coexistence_notice() {
        if ( !get_option( self::COEXIST_OPTION ) ) {
            return;
        }
        if ( !current_user_can( 'activate_plugins' ) ) {
            return;
        }
        echo '<div class="notice notice-error"><p>' . esc_html__( 'AP Family Archive shares data with AP Family Trees. Please update AP Family Trees to its core-adoption release first, then activate Archive.', 'ap-family-archive' ) . '</p></div>';
    }

}
