<?php

namespace UltraguardPro\modules\auto_updater;

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

use Automatic_Upgrader_Skin;
use Core_Upgrader;
use Plugin_Upgrader;
use Theme_Upgrader;
use UltraguardPro\core\BaseController;
use UltraguardPro\Plugin;

class UpdateEngine extends BaseController {

    public function __construct( ?Plugin $plugin = null ) {
        parent::__construct( $plugin );
    }

    public function get_pending_updates(): array {
        require_once ABSPATH . 'wp-admin/includes/update.php';
        wp_version_check();
        wp_update_plugins();
        wp_update_themes();

        $updates = [];

        foreach ( (array) get_plugin_updates() as $file => $plugin ) {
            $new_version = (string) ( $plugin->update->new_version ?? '' );
            $slug        = dirname( $file );
            $slug        = '.' === $slug ? basename( $file, '.php' ) : $slug;

            $updates[] = [
                'type'         => 'plugin',
                'slug'         => $slug,
                'file'         => $file,
                'name'         => (string) ( $plugin->Name ?? $slug ),
                'old_version'  => (string) ( $plugin->Version ?? '' ),
                'new_version'  => $new_version,
                'auto_allowed' => $this->should_auto_update( 'plugin', $slug, $new_version ),
            ];
        }

        foreach ( (array) get_theme_updates() as $slug => $theme ) {
            $updates[] = [
                'type'         => 'theme',
                'slug'         => $slug,
                'name'         => (string) $theme->get( 'Name' ),
                'old_version'  => (string) $theme->get( 'Version' ),
                'new_version'  => (string) $theme->update['new_version'],
                'auto_allowed' => $this->should_auto_update( 'theme', $slug, (string) $theme->update['new_version'] ),
            ];
        }

        require_once ABSPATH . 'wp-admin/includes/update-core.php';
        $core_updates = get_core_updates( [ 'dismissed' => false ] );
        if ( ! empty( $core_updates[0]->current ) && version_compare( $core_updates[0]->current, get_bloginfo( 'version' ), '>' ) ) {
            $updates[] = [
                'type'         => 'core',
                'slug'         => 'wordpress',
                'name'         => __( 'WordPress Core', 'ultraguard-security-suite' ),
                'old_version'  => get_bloginfo( 'version' ),
                'new_version'  => (string) $core_updates[0]->current,
                'auto_allowed' => $this->should_auto_update( 'core', 'wordpress', (string) $core_updates[0]->current ),
            ];
        }

        return $updates;
    }

    public function apply_plugin_update( string $slug, string $trigger_type = 'manual' ): bool {
        require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
        require_once ABSPATH . 'wp-admin/includes/update.php';
        wp_update_plugins();

        $updates = get_plugin_updates();
        foreach ( (array) $updates as $file => $plugin ) {
            $candidate = dirname( $file );
            $candidate = '.' === $candidate ? basename( $file, '.php' ) : $candidate;
            if ( $candidate !== $slug ) {
                continue;
            }

            $snapshot = $this->fire_pre_update_snapshot( 'plugin', $slug );
            $log_id   = $this->create_log_entry( 'plugin', $slug, (string) ( $plugin->Name ?? $slug ), (string) ( $plugin->Version ?? '' ), (string) ( $plugin->update->new_version ?? '' ), $trigger_type, $snapshot );
            $upgrader = new Plugin_Upgrader( new Automatic_Upgrader_Skin() );
            $result   = $upgrader->upgrade( $file );

            $success = $this->finalize_update_result( $log_id, ! is_wp_error( $result ) && false !== $result, is_wp_error( $result ) ? $result->get_error_message() : '' );
            $this->cleanup_stale_maintenance_file();

            return $success;
        }

        return false;
    }

    public function apply_theme_update( string $slug, string $trigger_type = 'manual' ): bool {
        require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
        require_once ABSPATH . 'wp-admin/includes/update.php';
        wp_update_themes();

        $updates = get_theme_updates();
        if ( empty( $updates[ $slug ] ) ) {
            return false;
        }

        $theme    = $updates[ $slug ];
        $snapshot = $this->fire_pre_update_snapshot( 'theme', $slug );
        $log_id   = $this->create_log_entry( 'theme', $slug, (string) $theme->get( 'Name' ), (string) $theme->get( 'Version' ), (string) $theme->update['new_version'], $trigger_type, $snapshot );
        $upgrader = new Theme_Upgrader( new Automatic_Upgrader_Skin() );
        $result   = $upgrader->upgrade( $slug );

        $success = $this->finalize_update_result( $log_id, ! is_wp_error( $result ) && false !== $result, is_wp_error( $result ) ? $result->get_error_message() : '' );
        $this->cleanup_stale_maintenance_file();

        return $success;
    }

    public function apply_core_update( string $trigger_type = 'manual' ): bool {
        require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
        require_once ABSPATH . 'wp-admin/includes/update-core.php';

        $updates = get_core_updates( [ 'dismissed' => false ] );
        if ( empty( $updates[0] ) ) {
            return false;
        }

        $target   = $updates[0];
        $snapshot = $this->fire_pre_update_snapshot( 'core', 'wordpress' );
        $log_id   = $this->create_log_entry( 'core', 'wordpress', __( 'WordPress Core', 'ultraguard-security-suite' ), get_bloginfo( 'version' ), (string) $target->current, $trigger_type, $snapshot );
        $upgrader = new Core_Upgrader( new Automatic_Upgrader_Skin() );
        $result   = $upgrader->upgrade( $target );

        $success = $this->finalize_update_result( $log_id, ! is_wp_error( $result ) && false !== $result, is_wp_error( $result ) ? $result->get_error_message() : '' );
        $this->cleanup_stale_maintenance_file();

        return $success;
    }

    public function apply_all_pending_updates( string $trigger_type = 'auto' ): array {
        $summary = [ 'applied' => 0, 'failed' => 0, 'skipped' => 0, 'trigger_type' => $trigger_type ];

        foreach ( $this->get_pending_updates() as $update ) {
            if ( empty( $update['auto_allowed'] ) && 'manual' !== $trigger_type ) {
                $summary['skipped']++;
                continue;
            }

            $ok = false;
            if ( 'plugin' === $update['type'] ) {
                $ok = $this->apply_plugin_update( (string) $update['slug'], $trigger_type );
            } elseif ( 'theme' === $update['type'] ) {
                $ok = $this->apply_theme_update( (string) $update['slug'], $trigger_type );
            } elseif ( 'core' === $update['type'] ) {
                $ok = $this->apply_core_update( $trigger_type );
            }

            if ( $ok ) {
                $summary['applied']++;
            } else {
                $summary['failed']++;
            }
        }

        do_action( 'ultraguard_pro/auto_updater/batch_complete', $summary );
        $this->cleanup_stale_maintenance_file();

        return $summary;
    }

    public function should_auto_update( string $type, string $slug, string $new_version ): bool {
        if ( 'plugin' === $type ) {
            if ( ! $this->plugin->settings->get_option( 'auto_updater_plugins_enabled', true ) ) {
                return false;
            }
            return ! in_array( $slug, $this->get_exclusions( 'plugin' ), true );
        }

        if ( 'theme' === $type ) {
            if ( ! $this->plugin->settings->get_option( 'auto_updater_themes_enabled', true ) ) {
                return false;
            }
            return ! in_array( $slug, $this->get_exclusions( 'theme' ), true );
        }

        if ( 'core' === $type ) {
            $is_major = version_compare( preg_replace( '/\.\d+$/', '.0', $new_version ), preg_replace( '/\.\d+$/', '.0', get_bloginfo( 'version' ) ), '>' );
            return $is_major
                ? (bool) $this->plugin->settings->get_option( 'auto_updater_core_major_enabled', false )
                : (bool) $this->plugin->settings->get_option( 'auto_updater_core_minor_enabled', true );
        }

        return false;
    }

    public function filter_plugin_auto_updates( $update, $item ) {
        $slug = dirname( (string) ( $item->plugin ?? '' ) );
        $slug = '.' === $slug ? basename( (string) ( $item->plugin ?? '' ), '.php' ) : $slug;
        return $this->should_auto_update( 'plugin', $slug, (string) ( $item->new_version ?? '' ) );
    }

    public function filter_theme_auto_updates( $update, $item ) {
        return $this->should_auto_update( 'theme', (string) ( $item->theme ?? '' ), (string) ( $item->new_version ?? '' ) );
    }

    public function filter_core_auto_updates( $update, $item ) {
        $version = is_object( $item ) ? (string) ( $item->current ?? '' ) : '';
        return $this->should_auto_update( 'core', 'wordpress', $version );
    }

    public function fire_pre_update_snapshot( string $type, string $slug ): string {
        $snapshot = '';
        do_action_ref_array( 'ultraguard_pro/auto_updater/before_update', [ $type, $slug, &$snapshot ] );
        return is_string( $snapshot ) ? $snapshot : '';
    }

    public function rollback_update( int $log_id ): bool {
        $table = $this->getTable( 'update_log' );
        $row   = $table ? $table->get( $log_id ) : null;
        if ( empty( $row['snapshot_path'] ) || ! file_exists( (string) $row['snapshot_path'] ) ) {
            return false;
        }

        require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
        $skin = new Automatic_Upgrader_Skin();

        if ( 'plugin' === $row['component_type'] ) {
            $upgrader = new Plugin_Upgrader( $skin );
            $result   = $upgrader->install( (string) $row['snapshot_path'] );
        } elseif ( 'theme' === $row['component_type'] ) {
            $upgrader = new Theme_Upgrader( $skin );
            $result   = $upgrader->install( (string) $row['snapshot_path'] );
        } else {
            return false;
        }

        if ( is_wp_error( $result ) || false === $result ) {
            return false;
        }

        $table->update( $log_id, [
            'status'         => 'rolled_back',
            'rolled_back_at' => current_time( 'mysql', true ),
        ] );

        return true;
    }

    public function log_upgrader_result( array $hook_extra ): void {
        $this->logInfo(
            'AutoUpdater: Upgrader process complete.',
            [ 'hook_extra' => $hook_extra ]
        );
    }

    public function get_update_stats(): array {
        $table = $this->getTable( 'update_log' );

        return [
            'applied_month' => $table && method_exists( $table, 'count_created_since' ) ? (int) $table->count_created_since( '-30 days', [ 'status' => 'success' ] ) : 0,
            'failed'        => $table && method_exists( $table, 'count_by_status' ) ? (int) $table->count_by_status( 'failed' ) : 0,
            'last_check'    => (string) get_option( 'auto_updater_last_check', '' ),
        ];
    }

    private function create_log_entry( string $type, string $slug, string $name, string $old_version, string $new_version, string $trigger_type, string $snapshot ): int {
        $table = $this->getTable( 'update_log' );
        if ( ! $table ) {
            return 0;
        }

        $id = $table->insert( [
            'component_type' => $type,
            'component_slug' => $slug,
            'component_name' => $name,
            'old_version'    => $old_version,
            'new_version'    => $new_version,
            'status'         => 'pending',
            'trigger_type'   => $trigger_type,
            'snapshot_path'  => $snapshot,
            'updated_by'     => get_current_user_id(),
        ] );

        return (int) $id;
    }

    private function finalize_update_result( int $log_id, bool $success, string $error ): bool {
        $table = $this->getTable( 'update_log' );
        if ( $table && $log_id > 0 ) {
            $table->update( $log_id, [
                'status'        => $success ? 'success' : 'failed',
                'error_message' => $error,
            ] );

            if ( ! $success ) {
                $row = $table->get( $log_id );
                if ( is_array( $row ) ) {
                    do_action( 'ultraguard_pro/auto_updater/update_failed', $row );
                }
            }
        }

        return $success;
    }

    private function get_exclusions( string $type ): array {
        $key  = 'plugin' === $type ? 'auto_updater_excluded_plugins' : 'auto_updater_excluded_themes';
        $list = preg_split( '/\r\n|\r|\n/', (string) $this->plugin->settings->get_option( $key, '' ) );

        return array_values( array_filter( array_map( 'sanitize_text_field', (array) $list ) ) );
    }

    private function cleanup_stale_maintenance_file(): void {
        $path = ABSPATH . '.maintenance';
        if ( ! file_exists( $path ) ) {
            return;
        }

        $upgrading = 0;
        include $path;

        if ( ! empty( $upgrading ) && ( time() - (int) $upgrading ) < 600 ) {
            return;
        }

        if ( wp_delete_file( $path ) ) {
            $this->logInfo(
                'AutoUpdater: Removed stale maintenance file.',
                [ 'path' => $path ]
            );
        }
    }
}
