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

class SITECL_Error_Reader {

    /** Maximum unique errors to process in one run. */
    private const MAX_ERRORS = 100;

    /** AI diagnosis limit — unlimited when user provides their own API key. */
    private const FREE_LIMIT = PHP_INT_MAX;

    /**
     * Parse error log, deduplicate, and return issues array.
     */
    public static function scan(): array {
        $log_path = self::detect_log_path();

        if ( ! $log_path || ! is_readable( $log_path ) ) {
            return [ [
                'type'     => 'error_reader',
                'severity' => 'info',
                'title'    => __( 'No PHP error log found', 'site-cliniq' ),
                'detail'   => __( 'Enable WP_DEBUG_LOG in wp-config.php to start capturing PHP errors.', 'site-cliniq' ),
            ] ];
        }

        $raw    = self::read_tail( $log_path, 2000 );
        $parsed = self::parse_entries( $raw );
        $deduped = self::deduplicate( $parsed );
        $limited = array_slice( $deduped, 0, self::MAX_ERRORS );

        $issues = [];
        $ai     = new SITECL_AI_Diagnosis();

        // Track monthly usage at site level so it works during cron (no logged-in user).
        $month_key = 'sitecl_ai_diagnoses_' . gmdate( 'Y_m' );
        $used      = (int) get_option( $month_key, 0 );

        foreach ( $limited as $error ) {
            $issue = [
                'type'      => 'error_reader',
                'severity'  => self::map_severity( $error['type'] ),
                'title'     => $error['type'] . ': ' . wp_trim_words( $error['message'], 12 ),
                'raw_error' => $error,
            ];

            if ( $used < self::get_monthly_limit() ) {
                $diagnosis = $ai->diagnose_error( $error );
                if ( ! is_wp_error( $diagnosis ) ) {
                    $issue['diagnosis'] = $diagnosis;
                    $issue['severity']  = $diagnosis['severity'] ?? $issue['severity'];
                    $used++;
                    update_option( $month_key, $used );
                }
            }

            $issues[] = $issue;
        }

        return $issues;
    }

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

    private static function detect_log_path(): string|false {
        // WP_DEBUG_LOG constant.
        if ( defined( 'WP_DEBUG_LOG' ) && is_string( WP_DEBUG_LOG ) && file_exists( WP_DEBUG_LOG ) ) {
            return WP_DEBUG_LOG;
        }

        $candidates = [
            WP_CONTENT_DIR . '/debug.log',
            ABSPATH . 'error_log',
            ini_get( 'error_log' ),
        ];

        foreach ( $candidates as $path ) {
            if ( $path && file_exists( $path ) ) {
                return $path;
            }
        }

        return false;
    }

    /** Read last $lines lines of file using WP_Filesystem. */
    private static function read_tail( string $path, int $lines ): string {
        global $wp_filesystem;

        if ( empty( $wp_filesystem ) ) {
            require_once ABSPATH . '/wp-admin/includes/file.php';
            WP_Filesystem();
        }

        $content = $wp_filesystem->get_contents( $path );
        if ( false === $content || '' === $content ) {
            return '';
        }

        $all_lines = explode( "\n", $content );
        $tail      = array_slice( $all_lines, -$lines );
        return implode( "\n", $tail );
    }

    private static function parse_entries( string $raw ): array {
        $pattern = '/\[(\d{2}-\w+-\d{4} \d{2}:\d{2}:\d{2} UTC)\] PHP (\w+(?: \w+)*): (.+?) in (.+?) on line (\d+)/';
        preg_match_all( $pattern, $raw, $matches, PREG_SET_ORDER );

        $entries = [];
        foreach ( $matches as $m ) {
            $entries[] = [
                'timestamp' => $m[1],
                'type'      => trim( $m[2] ),
                'message'   => trim( $m[3] ),
                'file'      => $m[4],
                'line'      => (int) $m[5],
                'count'     => 1,
            ];
        }

        return $entries;
    }

    private static function deduplicate( array $entries ): array {
        $map = [];
        foreach ( $entries as $e ) {
            $key = md5( $e['type'] . $e['message'] . $e['file'] . $e['line'] );
            if ( isset( $map[ $key ] ) ) {
                $map[ $key ]['count']++;
            } else {
                $map[ $key ] = $e;
            }
        }
        // Sort by count desc so most-frequent errors are diagnosed first.
        usort( $map, fn( $a, $b ) => $b['count'] <=> $a['count'] );
        return array_values( $map );
    }

    private static function map_severity( string $type ): string {
        $critical = [ 'Fatal error', 'Parse error' ];
        $warning  = [ 'Warning', 'Deprecated' ];

        if ( in_array( $type, $critical, true ) ) {
            return 'critical';
        }
        if ( in_array( $type, $warning, true ) ) {
            return 'warning';
        }
        return 'info';
    }

    private static function get_monthly_limit(): int {
        return self::FREE_LIMIT;
    }
}
