<?php
defined( 'ABSPATH' ) || exit;

class SITECL_Health_Score {

    /**
     * Run all health checks and return issues.
     */
    public static function scan(): array {
        $checks = [
            self::check_php_version(),
            self::check_wp_version(),
            self::check_memory_limit(),
            self::check_debug_mode(),
            self::check_ssl(),
            self::check_file_permissions(),
            self::check_db_connection(),
        ];

        // Remove nulls (passing checks with no issue to report).
        $issues = array_filter( $checks );
        $issues = array_values( $issues );

        // Calculate and store score.
        $grade = self::calculate_grade( $issues );
        self::persist_score( $grade, $issues );

        return $issues;
    }

    public static function calculate_grade( array $issues ): array {
        $critical = 0;
        $warnings = 0;
        $info     = 0;

        foreach ( $issues as $issue ) {
            match ( $issue['severity'] ?? 'info' ) {
                'critical' => $critical++,
                'warning'  => $warnings++,
                default    => $info++,
            };
        }

        if ( $critical > 0 )      { $grade = 'F'; $score = 1; }
        elseif ( $warnings >= 2 ) { $grade = 'D'; $score = 2; }
        elseif ( $warnings === 1 ) { $grade = 'C'; $score = 3; }
        elseif ( $info >= 1 )     { $grade = 'B'; $score = 4; }
        else                      { $grade = 'A'; $score = 5; }

        return [ 'grade' => $grade, 'score' => $score, 'critical' => $critical, 'warnings' => $warnings, 'info' => $info ];
    }

    // -------------------------------------------------------------------------
    // Individual checks — return issue array or null (pass).
    // -------------------------------------------------------------------------

    private static function check_php_version(): ?array {
        if ( version_compare( PHP_VERSION, '8.1', '>=' ) ) {
            return null;
        }

        $severity = version_compare( PHP_VERSION, '8.0', '<' ) ? 'critical' : 'warning';

        return [
            'type'     => 'health_score',
            'severity' => $severity,
            /* translators: %s: current PHP version number */
            'title'    => sprintf( __( 'PHP %s is outdated', 'site-cliniq' ), PHP_VERSION ),
            'detail'   => __( 'Upgrade to PHP 8.1 or higher for better performance and security. Contact your host.', 'site-cliniq' ),
        ];
    }

    private static function check_wp_version(): ?array {
        global $wp_version;
        $latest = self::fetch_latest_wp_version();

        if ( ! $latest || version_compare( $wp_version, $latest, '>=' ) ) {
            return null;
        }

        return [
            'type'     => 'health_score',
            'severity' => 'warning',
            /* translators: %1$s: latest WordPress version number, %2$s: currently installed WordPress version number */
            'title'    => sprintf( __( 'WordPress %1$s available (you have %2$s)', 'site-cliniq' ), $latest, $wp_version ),
            'detail'   => __( 'Go to Dashboard → Updates and install the latest WordPress version.', 'site-cliniq' ),
        ];
    }

    private static function check_memory_limit(): ?array {
        $limit_str = ini_get( 'memory_limit' );
        $limit_mb  = self::parse_memory( $limit_str );

        if ( $limit_mb >= 256 ) {
            return null;
        }

        return [
            'type'     => 'health_score',
            'severity' => $limit_mb < 128 ? 'critical' : 'warning',
            /* translators: %s: current PHP memory limit (e.g. 128M) */
            'title'    => sprintf( __( 'PHP memory limit is only %s', 'site-cliniq' ), $limit_str ),
            'detail'   => __( 'Add "define( \'WP_MEMORY_LIMIT\', \'256M\' );" to wp-config.php or ask your host to increase PHP memory.', 'site-cliniq' ),
        ];
    }

    private static function check_debug_mode(): ?array {
        if ( ! ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ) {
            return null;
        }

        return [
            'type'     => 'health_score',
            'severity' => 'warning',
            'title'    => __( 'WP_DEBUG is enabled on a live site', 'site-cliniq' ),
            'detail'   => __( 'Set "define( \'WP_DEBUG\', false );" in wp-config.php. Debug mode exposes errors to visitors.', 'site-cliniq' ),
        ];
    }

    private static function check_ssl(): ?array {
        if ( is_ssl() ) {
            return null;
        }

        return [
            'type'     => 'health_score',
            'severity' => 'critical',
            'title'    => __( 'Site is not using HTTPS', 'site-cliniq' ),
            'detail'   => __( 'Enable a free SSL certificate through your host or Cloudflare. HTTPS is required for SEO and security.', 'site-cliniq' ),
        ];
    }

    private static function check_file_permissions(): ?array {
        $wp_config = ABSPATH . 'wp-config.php';

        if ( ! file_exists( $wp_config ) ) {
            return null;
        }

        $perms = fileperms( $wp_config ) & 0777;

        // 640 or tighter is fine; 644+ is acceptable; 666+ is a problem.
        if ( $perms <= 0644 ) {
            return null;
        }

        return [
            'type'     => 'health_score',
            'severity' => 'critical',
            /* translators: %s: Unix file permission value in octal (e.g. 777) */
            'title'    => sprintf( __( 'wp-config.php permissions are too open (%s)', 'site-cliniq' ), decoct( $perms ) ),
            'detail'   => __( 'Run: chmod 640 wp-config.php via SSH or ask your host to fix file permissions.', 'site-cliniq' ),
        ];
    }

    private static function check_db_connection(): ?array {
        global $wpdb;
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $result = $wpdb->get_var( 'SELECT 1' );

        if ( $result === '1' ) {
            return null;
        }

        return [
            'type'     => 'health_score',
            'severity' => 'critical',
            'title'    => __( 'Database connection issue detected', 'site-cliniq' ),
            'detail'   => __( 'WordPress cannot reliably query the database. Check your wp-config.php credentials and contact your host.', 'site-cliniq' ),
        ];
    }

    // -------------------------------------------------------------------------

    private static function fetch_latest_wp_version(): ?string {
        $cached = get_transient( 'sitecl_latest_wp_version' );
        if ( $cached ) {
            return $cached;
        }

        $response = wp_remote_get( 'https://api.wordpress.org/core/version-check/1.7/' );
        if ( is_wp_error( $response ) ) {
            return null;
        }

        $body = json_decode( wp_remote_retrieve_body( $response ), true );
        $version = $body['offers'][0]['version'] ?? null;

        if ( $version ) {
            set_transient( 'sitecl_latest_wp_version', $version, HOUR_IN_SECONDS * 12 );
        }

        return $version;
    }

    private static function parse_memory( string $val ): int {
        $val  = strtoupper( trim( $val ) );
        $unit = substr( $val, -1 );
        $num  = (int) $val;

        return match ( $unit ) {
            'G' => $num * 1024,
            'M' => $num,
            'K' => (int) ( $num / 1024 ),
            default => $num,
        };
    }

    private static function persist_score( array $grade_data, array $issues ): void {
        global $wpdb;
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
        $wpdb->insert(
            $wpdb->prefix . 'sitecl_health_scores',
            [
                'score'       => $grade_data['score'],
                'grade'       => $grade_data['grade'],
                'issues_json' => wp_json_encode( $issues ),
                'scanned_at'  => current_time( 'mysql' ),
            ],
            [ '%d', '%s', '%s', '%s' ]
        );

        // Keep only the 28 most recent rows (4 weeks of daily scans).
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $keep_ids = $wpdb->get_col(
            "SELECT id FROM `{$wpdb->prefix}sitecl_health_scores` ORDER BY scanned_at DESC LIMIT 28"
        );

        if ( ! empty( $keep_ids ) ) {
            // IDs are cast to int — no user input. Table name uses $wpdb->prefix + literal only.
            $int_ids = array_map( 'intval', $keep_ids );
            $wpdb->query( 'DELETE FROM `' . $wpdb->prefix . 'sitecl_health_scores` WHERE id NOT IN (' . implode( ',', $int_ids ) . ')' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
        }
    }
}
