<?php

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

class Niwa_AI_Admin_Autonomy_Site_Discovery {
    const CACHE_TRANSIENT = 'niwa_ai_admin_site_discovery_v1';

    private $db_intelligence;
    private $workspace;

    public function __construct( $db_intelligence = null, $workspace = null ) {
        $this->db_intelligence = $db_intelligence;
        $this->workspace       = $workspace;
    }

    public function register_hooks() {
        add_action( 'activated_plugin', array( $this, 'flush_cache' ) );
        add_action( 'deactivated_plugin', array( $this, 'flush_cache' ) );
        add_action( 'switch_theme', array( $this, 'flush_cache' ) );
        add_action( 'upgrader_process_complete', array( $this, 'flush_cache' ) );
    }

    public function flush_cache() {
        delete_transient( self::CACHE_TRANSIENT );
        if ( $this->db_intelligence && method_exists( $this->db_intelligence, 'flush_cache' ) ) {
            $this->db_intelligence->flush_cache();
        }
    }

    public function get_snapshot( $force = false ) {
        if ( ! $force ) {
            $cached = get_transient( self::CACHE_TRANSIENT );
            if ( is_array( $cached ) && ! empty( $cached ) ) {
                return $cached;
            }
        }

        $snapshot = $this->build_snapshot();
        set_transient( self::CACHE_TRANSIENT, $snapshot, 15 * MINUTE_IN_SECONDS );

        if ( $this->workspace && method_exists( $this->workspace, 'write_json_artifact' ) ) {
            $this->workspace->write_json_artifact( 'site-discovery-latest.json', $snapshot, 'snapshots' );
        }

        return $snapshot;
    }

    public function get_context_blob( $max_chars = 2400 ) {
        $snapshot = $this->get_snapshot();
        $lines    = array();

        if ( ! empty( $snapshot['site']['host'] ) ) {
            $lines[] = 'Host: ' . $snapshot['site']['host'];
        }
        if ( ! empty( $snapshot['site']['name'] ) ) {
            $lines[] = 'Site: ' . $snapshot['site']['name'];
        }
        if ( ! empty( $snapshot['theme']['name'] ) ) {
            $lines[] = 'Active theme: ' . $snapshot['theme']['name'] . ( ! empty( $snapshot['theme']['version'] ) ? ' ' . $snapshot['theme']['version'] : '' );
        }

        if ( ! empty( $snapshot['plugins'] ) ) {
            $plugin_names = array();
            foreach ( array_slice( $snapshot['plugins'], 0, 8 ) as $plugin ) {
                if ( empty( $plugin['name'] ) ) {
                    continue;
                }
                $plugin_names[] = $plugin['name'];
            }
            if ( ! empty( $plugin_names ) ) {
                $lines[] = 'Active plugins: ' . implode( ', ', $plugin_names );
            }
        }

        if ( ! empty( $snapshot['content_types']['custom_post_types'] ) ) {
            $labels = array();
            foreach ( array_slice( $snapshot['content_types']['custom_post_types'], 0, 8 ) as $item ) {
                if ( empty( $item['name'] ) ) {
                    continue;
                }
                $labels[] = $item['name'];
            }
            if ( ! empty( $labels ) ) {
                $lines[] = 'Custom post types: ' . implode( ', ', $labels );
            }
        }

        if ( ! empty( $snapshot['content_types']['taxonomies'] ) ) {
            $labels = array();
            foreach ( array_slice( $snapshot['content_types']['taxonomies'], 0, 8 ) as $item ) {
                if ( empty( $item['name'] ) ) {
                    continue;
                }
                $labels[] = $item['name'];
            }
            if ( ! empty( $labels ) ) {
                $lines[] = 'Taxonomies: ' . implode( ', ', $labels );
            }
        }

        if ( ! empty( $snapshot['wordpress']['shortcodes'] ) ) {
            $lines[] = 'Shortcodes: ' . implode( ', ', array_slice( $snapshot['wordpress']['shortcodes'], 0, 12 ) );
        }

        if ( ! empty( $snapshot['database']['notable_tables'] ) ) {
            $tables = array();
            foreach ( array_slice( $snapshot['database']['notable_tables'], 0, 8 ) as $table ) {
                if ( empty( $table['name'] ) ) {
                    continue;
                }
                $tables[] = $table['name'];
            }
            if ( ! empty( $tables ) ) {
                $lines[] = 'Notable DB tables: ' . implode( ', ', $tables );
            }
        }

        if ( ! empty( $snapshot['metrics_sources'] ) ) {
            $labels = array();
            foreach ( $snapshot['metrics_sources'] as $source ) {
                if ( ! empty( $source['label'] ) ) {
                    $labels[] = $source['label'];
                }
            }
            if ( ! empty( $labels ) ) {
                $lines[] = 'Local metrics sources: ' . implode( ', ', $labels );
            }
        }

        $blob = implode( "\n", array_filter( $lines ) );
        if ( mb_strlen( $blob ) > $max_chars ) {
            $blob = rtrim( mb_substr( $blob, 0, $max_chars - 3 ) ) . '...';
        }

        return $blob;
    }

    private function build_snapshot() {
        require_once ABSPATH . 'wp-admin/includes/plugin.php';

        $site                = $this->build_site_info();
        $theme               = $this->build_theme_info();
        $plugins             = $this->build_plugins();
        $wordpress_facts     = $this->build_wordpress_facts();
        $database_facts      = $this->db_intelligence && method_exists( $this->db_intelligence, 'get_table_index' ) ? $this->db_intelligence->get_table_index( $plugins ) : array();
        $plugin_table_lookup = $this->group_tables_by_plugin( $database_facts );

        foreach ( $plugins as &$plugin ) {
            $slug = isset( $plugin['slug'] ) ? (string) $plugin['slug'] : '';
            $plugin['possible_tables'] = isset( $plugin_table_lookup[ $slug ] ) ? $plugin_table_lookup[ $slug ] : array();
        }
        unset( $plugin );

        return array(
            'generated_at'  => time(),
            'site'          => $site,
            'theme'         => $theme,
            'plugins'       => $plugins,
            'content_types' => array(
                'custom_post_types' => $this->build_post_types(),
                'taxonomies'        => $this->build_taxonomies(),
            ),
            'wordpress'     => $wordpress_facts,
            'database'      => array(
                'notable_tables' => $database_facts,
                'table_count'    => count( $database_facts ),
            ),
            'metrics_sources' => $this->detect_metrics_sources( $plugins, $database_facts ),
        );
    }

    private function build_site_info() {
        return array(
            'name'    => get_bloginfo( 'name' ),
            'host'    => wp_parse_url( home_url( '/' ), PHP_URL_HOST ),
            'url'     => home_url( '/' ),
            'wp_version' => get_bloginfo( 'version' ),
            'language'   => determine_locale(),
        );
    }

    private function build_theme_info() {
        $theme = wp_get_theme();
        $root  = $theme->get_stylesheet_directory();

        return array(
            'name'         => $theme->get( 'Name' ),
            'stylesheet'   => $theme->get_stylesheet(),
            'template'     => $theme->get_template(),
            'version'      => $theme->get( 'Version' ),
            'page_templates' => array_values( array_keys( (array) $theme->get_page_templates() ) ),
            'touchpoints'  => $this->scan_code_root( $root, 120 ),
        );
    }

    private function build_plugins() {
        $plugins          = array();
        $all_plugins      = (array) get_plugins();
        $active_plugins   = (array) get_option( 'active_plugins', array() );
        $network_active   = is_multisite() ? array_keys( (array) get_site_option( 'active_sitewide_plugins', array() ) ) : array();
        $active_files     = array_values( array_unique( array_merge( $active_plugins, $network_active ) ) );

        foreach ( $active_files as $plugin_file ) {
            if ( empty( $all_plugins[ $plugin_file ] ) ) {
                continue;
            }

            $header    = $all_plugins[ $plugin_file ];
            $slug      = dirname( $plugin_file );
            $slug      = '.' === $slug ? basename( $plugin_file, '.php' ) : $slug;
            $main_path = WP_PLUGIN_DIR . '/' . $plugin_file;
            $root      = is_dir( dirname( $main_path ) ) ? dirname( $main_path ) : $main_path;

            $plugins[] = array(
                'slug'           => sanitize_title( $slug ),
                'name'           => isset( $header['Name'] ) ? (string) $header['Name'] : $slug,
                'version'        => isset( $header['Version'] ) ? (string) $header['Version'] : '',
                'description'    => isset( $header['Description'] ) ? wp_strip_all_tags( (string) $header['Description'] ) : '',
                'author'         => isset( $header['AuthorName'] ) ? (string) $header['AuthorName'] : '',
                'main_file'      => $plugin_file,
                'main_path'      => $main_path,
                'scan'           => $this->scan_code_root( $root, 140 ),
                'possible_tables' => array(),
            );
        }

        usort(
            $plugins,
            function ( $a, $b ) {
                return strcmp( strtolower( (string) $a['name'] ), strtolower( (string) $b['name'] ) );
            }
        );

        return $plugins;
    }

    private function build_wordpress_facts() {
        global $shortcode_tags;

        $routes      = rest_get_server()->get_routes();
        $namespaces  = array();
        foreach ( array_keys( (array) $routes ) as $route ) {
            $segments = explode( '/', trim( (string) $route, '/' ) );
            if ( empty( $segments[0] ) ) {
                continue;
            }
            $namespaces[] = $segments[0];
        }

        return array(
            'shortcodes'   => array_values( array_slice( array_keys( (array) $shortcode_tags ), 0, 60 ) ),
            'rest_namespaces' => array_values( array_unique( array_filter( $namespaces ) ) ),
            'cron_hooks'   => $this->get_cron_hooks(),
        );
    }

    private function build_post_types() {
        $post_types = get_post_types( array(), 'objects' );
        $items      = array();

        foreach ( (array) $post_types as $post_type ) {
            if ( ! is_object( $post_type ) || empty( $post_type->name ) ) {
                continue;
            }

            $items[] = array(
                'name'       => (string) $post_type->name,
                'label'      => isset( $post_type->label ) ? (string) $post_type->label : (string) $post_type->name,
                'public'     => ! empty( $post_type->public ),
                'built_in'   => ! empty( $post_type->_builtin ),
                'rest_base'  => isset( $post_type->rest_base ) ? (string) $post_type->rest_base : '',
            );
        }

        return array_values( $items );
    }

    private function build_taxonomies() {
        $taxonomies = get_taxonomies( array(), 'objects' );
        $items      = array();

        foreach ( (array) $taxonomies as $taxonomy ) {
            if ( ! is_object( $taxonomy ) || empty( $taxonomy->name ) ) {
                continue;
            }

            $items[] = array(
                'name'       => (string) $taxonomy->name,
                'label'      => isset( $taxonomy->label ) ? (string) $taxonomy->label : (string) $taxonomy->name,
                'public'     => ! empty( $taxonomy->public ),
                'built_in'   => ! empty( $taxonomy->_builtin ),
                'post_types' => isset( $taxonomy->object_type ) ? array_values( (array) $taxonomy->object_type ) : array(),
            );
        }

        return array_values( $items );
    }

    private function get_cron_hooks() {
        $cron = function_exists( '_get_cron_array' ) ? _get_cron_array() : array();
        $hooks = array();

        foreach ( (array) $cron as $timestamp => $scheduled ) {
            foreach ( (array) $scheduled as $hook => $events ) {
                $hooks[] = (string) $hook;
            }
        }

        $hooks = array_values( array_unique( array_filter( $hooks ) ) );
        sort( $hooks );

        return array_slice( $hooks, 0, 80 );
    }

    private function scan_code_root( $root, $max_files ) {
        $facts = array(
            'shortcodes'    => array(),
            'post_types'    => array(),
            'taxonomies'    => array(),
            'rest_routes'   => array(),
            'cron_hooks'    => array(),
            'option_keys'   => array(),
            'post_meta_keys' => array(),
            'render_hooks'  => array(),
            'template_files' => array(),
        );

        if ( empty( $root ) || ! file_exists( $root ) ) {
            return $facts;
        }

        $files = $this->collect_scan_files( $root, $max_files );
        foreach ( $files as $file ) {
            $contents = @file_get_contents( $file );
            if ( false === $contents || '' === $contents ) {
                continue;
            }

            $facts['shortcodes']     = array_merge( $facts['shortcodes'], $this->match_all( $contents, '/add_shortcode\s*\(\s*[\'"]([^\'"]+)[\'"]/i' ) );
            $facts['post_types']     = array_merge( $facts['post_types'], $this->match_all( $contents, '/register_post_type\s*\(\s*[\'"]([^\'"]+)[\'"]/i' ) );
            $facts['taxonomies']     = array_merge( $facts['taxonomies'], $this->match_all( $contents, '/register_taxonomy\s*\(\s*[\'"]([^\'"]+)[\'"]/i' ) );
            $facts['render_hooks']   = array_merge( $facts['render_hooks'], $this->match_frontend_hooks( $contents ) );
            $facts['option_keys']    = array_merge( $facts['option_keys'], $this->match_all( $contents, '/(?:get|update|delete|add)_option\s*\(\s*[\'"]([^\'"]+)[\'"]/i' ) );
            $facts['post_meta_keys'] = array_merge( $facts['post_meta_keys'], $this->match_all( $contents, '/(?:get|update|delete)_post_meta\s*\([^,]+,\s*[\'"]([^\'"]+)[\'"]/i' ) );
            $facts['cron_hooks']     = array_merge( $facts['cron_hooks'], $this->match_all( $contents, '/wp_schedule_(?:event|single_event)\s*\([^,]+,\s*[\'"][^\'"]+[\'"]\s*,\s*[\'"]([^\'"]+)[\'"]/i' ) );

            if ( preg_match_all( '/register_rest_route\s*\(\s*[\'"]([^\'"]+)[\'"]\s*,\s*[\'"]([^\'"]+)[\'"]/i', $contents, $matches, PREG_SET_ORDER ) ) {
                foreach ( $matches as $match ) {
                    $facts['rest_routes'][] = trim( (string) $match[1], '/' ) . ':' . trim( (string) $match[2], '/' );
                }
            }

            $relative = $this->to_relative_path( $file );
            if ( preg_match( '#(?:templates?|views?|blocks?|widgets?|elementor|shortcodes?)#i', $relative ) ) {
                $facts['template_files'][] = $relative;
            }
        }

        foreach ( $facts as $key => $values ) {
            $values      = array_values( array_unique( array_filter( array_map( 'strval', $values ) ) ) );
            sort( $values );
            $facts[ $key ] = array_slice( $values, 0, 40 );
        }

        return $facts;
    }

    private function collect_scan_files( $root, $max_files ) {
        $files = array();
        $max_files = max( 20, intval( $max_files ) );

        try {
            $iterator = new RecursiveIteratorIterator(
                new RecursiveCallbackFilterIterator(
                    new RecursiveDirectoryIterator( $root, FilesystemIterator::SKIP_DOTS ),
                    function ( $current ) {
                        $name = $current->getFilename();
                        if ( $current->isDir() ) {
                            return ! in_array( $name, array( '.git', 'node_modules', 'vendor', 'assets', 'dist', 'build', 'languages' ), true );
                        }

                        return preg_match( '/\.(php|inc|js|json)$/i', $name ) && $current->getSize() <= 512000;
                    }
                ),
                RecursiveIteratorIterator::LEAVES_ONLY
            );
        } catch ( Throwable $e ) {
            return $files;
        }

        foreach ( $iterator as $file_info ) {
            if ( count( $files ) >= $max_files ) {
                break;
            }
            if ( $file_info instanceof SplFileInfo && $file_info->isFile() ) {
                $files[] = $file_info->getPathname();
            }
        }

        return $files;
    }

    private function match_all( $contents, $pattern ) {
        if ( ! preg_match_all( $pattern, $contents, $matches ) ) {
            return array();
        }

        return isset( $matches[1] ) ? array_values( array_filter( array_map( 'trim', $matches[1] ) ) ) : array();
    }

    private function match_frontend_hooks( $contents ) {
        $hooks = $this->match_all( $contents, '/add_(?:action|filter)\s*\(\s*[\'"]([^\'"]+)[\'"]/i' );
        $out   = array();

        foreach ( $hooks as $hook ) {
            if ( preg_match( '/^(wp_head|wp_footer|template_|the_content|loop_|woocommerce_|elementor_|wp_enqueue_scripts|rest_api_init|init)$/', $hook ) ) {
                $out[] = $hook;
            }
        }

        return $out;
    }

    private function group_tables_by_plugin( $tables ) {
        $grouped = array();
        foreach ( (array) $tables as $table ) {
            if ( empty( $table['owner_hints'] ) || ! is_array( $table['owner_hints'] ) ) {
                continue;
            }
            foreach ( $table['owner_hints'] as $owner ) {
                if ( empty( $owner['slug'] ) || empty( $table['name'] ) ) {
                    continue;
                }
                $grouped[ $owner['slug'] ][] = array(
                    'name'       => $table['name'],
                    'confidence' => isset( $owner['confidence'] ) ? intval( $owner['confidence'] ) : 0,
                );
            }
        }

        return $grouped;
    }

    private function detect_metrics_sources( $plugins, $tables ) {
        $sources = array();

        foreach ( (array) $plugins as $plugin ) {
            $name = isset( $plugin['name'] ) ? (string) $plugin['name'] : '';
            $slug = isset( $plugin['slug'] ) ? (string) $plugin['slug'] : '';
            if ( '' === $name ) {
                continue;
            }

            if ( in_array( $slug, array( 'woocommerce', 'niwa-ai', 'google-site-kit', 'google-analytics-for-wordpress', 'independent-analytics', 'exactmetrics' ), true ) ) {
                $sources[] = array(
                    'label' => $name,
                    'slug'  => $slug,
                );
            }
        }

        foreach ( (array) $tables as $table ) {
            if ( empty( $table['metrics_signals'] ) || empty( $table['name'] ) ) {
                continue;
            }
            $sources[] = array(
                'label' => $table['name'],
                'slug'  => sanitize_title( $table['name'] ),
            );
        }

        $unique = array();
        foreach ( $sources as $source ) {
            $key = isset( $source['slug'] ) ? (string) $source['slug'] : md5( wp_json_encode( $source ) );
            $unique[ $key ] = $source;
        }

        return array_values( $unique );
    }

    private function to_relative_path( $path ) {
        $path    = str_replace( '\\', '/', (string) $path );
        $abspath = str_replace( '\\', '/', (string) ABSPATH );
        if ( 0 === strpos( $path, $abspath ) ) {
            return ltrim( substr( $path, strlen( $abspath ) ), '/' );
        }

        return $path;
    }
}
