<?php
/**
 * Helpers for scanning translation strings from language directories.
 *
 * @package WPR_Translate
 */

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

require_once WPR_TRANSLATE_PATH . 'includes/admin/string-export.php';
require_once WPR_TRANSLATE_PATH . 'includes/admin/string-parser.php';
require_once WPR_TRANSLATE_PATH . 'includes/admin/string-storage.php';
require_once WPR_TRANSLATE_PATH . 'includes/admin/string-actions.php';

/**
 * Handle admin actions submitted from the string translation screen.
 */
function wpr_translate_admin_handle_strings_actions() {
    // Ensure only admins can trigger string actions.
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }

    // Handle delete requests for selected strings.
    if ( isset( $_POST['wpr_translate_delete_nonce'] ) ) {
        wpr_translate_admin_handle_delete_strings();
    }

    if ( isset( $_POST['wpr_translate_scan_nonce'] ) ) {
        // Validate nonce before running a scan.
        check_admin_referer( 'wpr_translate_scan_strings', 'wpr_translate_scan_nonce' );

        // Run the scan and surface feedback.
        $result = wpr_translate_admin_scan_strings();

        if ( is_wp_error( $result ) ) {
            add_settings_error(
                'wpr_translate_strings',
                'wpr_translate_strings_scan_error',
                $result->get_error_message(),
                'error'
            );
        } else {
            $count = isset( $result['new'] ) ? (int) $result['new'] : 0;

            $message = sprintf(
                _n(
                    'Scan completed. %d new string was registered.',
                    'Scan completed. %d new strings were registered.',
                    $count,
                    'wpr-translate'
                ),
                $count
            );

            add_settings_error(
                'wpr_translate_strings',
                'wpr_translate_strings_scan_success',
                $message,
                'updated'
            );
        }
    }

    if ( isset( $_POST['wpr_translate_reset_nonce'] ) ) {
        // Validate nonce before clearing stored strings.
        check_admin_referer( 'wpr_translate_reset_strings', 'wpr_translate_reset_nonce' );

        // Reset stored strings and report status.
        $reset = wpr_translate_admin_reset_strings();

        if ( is_wp_error( $reset ) ) {
            add_settings_error(
                'wpr_translate_strings',
                'wpr_translate_strings_reset_error',
                $reset->get_error_message(),
                'error'
            );
        } else {
            add_settings_error(
                'wpr_translate_strings',
                'wpr_translate_strings_reset',
                __( 'All translation strings have been cleared.', 'wpr-translate' ),
                'updated'
            );
        }
    }

    if ( isset( $_POST['wpr_translate_generate_nonce'] ) ) {
        // Validate nonce before generating translation files.
        check_admin_referer( 'wpr_translate_generate_files', 'wpr_translate_generate_nonce' );

        // Generate MO files and report results.
        $result = wpr_translate_admin_generate_translation_files();

        if ( is_wp_error( $result ) ) {
            add_settings_error(
                'wpr_translate_strings',
                'wpr_translate_generate_error',
                $result->get_error_message(),
                'error'
            );
        } else {
            $files_count   = isset( $result['files'] ) ? (int) $result['files'] : 0;
            $strings_count = isset( $result['strings'] ) ? (int) $result['strings'] : 0;

            if ( $files_count > 0 || $strings_count > 0 ) {
                $message = sprintf(
                    _n(
                        'Generated %1$d file covering %2$d translation.',
                        'Generated %1$d files covering %2$d translations.',
                        $files_count,
                        'wpr-translate'
                    ),
                    $files_count,
                    $strings_count
                );
            } else {
                $message = __( 'No new translations were ready for export.', 'wpr-translate' );
            }

            add_settings_error(
                'wpr_translate_strings',
                'wpr_translate_generate_success',
                $message,
                $files_count > 0 ? 'updated' : 'info'
            );

            if ( isset( $result['errors'] ) && is_array( $result['errors'] ) ) {
                // Surface any per-file export warnings.
                foreach ( $result['errors'] as $index => $error_message ) {
                    if ( '' === trim( $error_message ) ) {
                        continue;
                    }

                    add_settings_error(
                        'wpr_translate_strings',
                        'wpr_translate_generate_warning_' . $index,
                        $error_message,
                        'error'
                    );
                }
            }
        }
    }
}

/**
 * Scan language directories and persist discovered strings.
 *
 * @return array|WP_Error
 */
function wpr_translate_admin_scan_strings() {
    // Load configured languages for scanning.
    $languages = get_option( 'wpr_translate_languages', array() );

    if ( empty( $languages ) ) {
        return new WP_Error( 'wpr_translate_missing_languages', __( 'Add at least one language before scanning for strings.', 'wpr-translate' ) );
    }

    if ( ! function_exists( 'wpr_translate_admin_get_default_language_code' ) ) {
        return new WP_Error( 'wpr_translate_missing_helper', __( 'Default language helper is unavailable.', 'wpr-translate' ) );
    }

    // Resolve the default language for translation decisions.
    $default_code = wpr_translate_admin_get_default_language_code( $languages );

    if ( '' === $default_code ) {
        return new WP_Error( 'wpr_translate_no_default_language', __( 'Configure a default language before scanning for strings.', 'wpr-translate' ) );
    }

    // Build lookup maps and retrieve scan targets.
    $maps                = wpr_translate_admin_build_language_maps( $languages );
    $targets             = wpr_translate_admin_get_scan_targets();
    $state               = get_option( 'wpr_translate_scan_state', array() );
    $languages_signature = md5( wp_json_encode( $languages ) );
    if ( ! is_array( $state ) ) {
        $state = array();
    }
    $updated_state = array();

    if ( empty( $targets ) ) {
        return array(
            'new' => 0,
        );
    }

    // Collect detected strings across all targets.
    $detected = array();

    foreach ( $targets as $target ) {
        $path           = isset( $target['path'] ) ? $target['path'] : '';
        $context        = isset( $target['context'] ) ? $target['context'] : '';
        $languages_path = isset( $target['languages_path'] ) ? $target['languages_path'] : '';

        if ( '' === $path || '' === $context ) {
            continue;
        }

        // Resolve the languages directory used to find and validate translation files.
        if ( '' === $languages_path ) {
            $languages_path = wpr_translate_admin_locate_languages_directory( $path );
        }

        if ( '' === $languages_path ) {
            continue;
        }

        // Skip scanning when the directory and configured languages have not changed since the last successful run.
        // Compute latest modification time for the languages directory.
        $current_mtime = wpr_translate_admin_get_languages_directory_mtime( $languages_path );

        $previous_state     = isset( $state[ $context ] ) ? $state[ $context ] : array();
        $previous_mtime     = is_array( $previous_state ) ? ( isset( $previous_state['mtime'] ) ? (int) $previous_state['mtime'] : 0 ) : (int) $previous_state;
        $previous_languages = is_array( $previous_state ) && isset( $previous_state['languages'] ) ? $previous_state['languages'] : '';

        if ( false !== $current_mtime && $previous_mtime === $current_mtime && $previous_languages === $languages_signature ) {
            // Skip unchanged targets and keep their state updated.
            $updated_state[ $context ] = array(
                'mtime'     => $current_mtime,
                'languages' => $languages_signature,
            );
            continue;
        }

        // Collect strings for the target context.
        $strings = wpr_translate_admin_collect_strings_from_path( $path, $context, $maps['locale'], $maps['code'] );

        if ( empty( $strings ) ) {
            if ( false !== $current_mtime ) {
                $updated_state[ $context ] = array(
                    'mtime'     => $current_mtime,
                    'languages' => $languages_signature,
                );
            }
            continue;
        }

        // Merge detected strings into the global set.
        $detected = wpr_translate_admin_merge_detected_strings( $detected, $strings );

        if ( false !== $current_mtime ) {
            $updated_state[ $context ] = array(
                'mtime'     => $current_mtime,
                'languages' => $languages_signature,
            );
        }
    }

    // Persist the scan state for future comparisons.
    update_option( 'wpr_translate_scan_state', $updated_state );

    if ( empty( $detected ) ) {
        return array(
            'new' => 0,
        );
    }

    // Store newly detected strings and return the count.
    $inserted = wpr_translate_admin_persist_detected_strings( $detected, $languages, $default_code );

    return array(
        'new' => $inserted,
    );
}

/**
 * Determine the latest modification time within a languages directory.
 *
 * @param string $languages_path Languages directory path.
 *
 * @return int|false
 */
function wpr_translate_admin_get_languages_directory_mtime( $languages_path ) {
    // Ensure the directory exists before scanning.
    if ( '' === $languages_path || ! is_dir( $languages_path ) || ! is_readable( $languages_path ) ) {
        return false;
    }

    // Start with the directory's mtime.
    $latest_mtime = filemtime( $languages_path );

    if ( false === $latest_mtime ) {
        $latest_mtime = 0;
    }

    try {
        $directory = new RecursiveDirectoryIterator( $languages_path, RecursiveDirectoryIterator::SKIP_DOTS );
        $iterator  = new RecursiveIteratorIterator( $directory );
    } catch ( Exception $exception ) {
        return $latest_mtime;
    }

    foreach ( $iterator as $file ) {
        // Track the latest modified file in the directory tree.
        if ( ! $file instanceof SplFileInfo || ! $file->isFile() ) {
            continue;
        }

        $mtime = $file->getMTime();

        if ( $mtime > $latest_mtime ) {
            $latest_mtime = $mtime;
        }
    }

    return $latest_mtime;
}

/**
 * Reset stored translation strings.
 *
 * @return true|WP_Error
 */
function wpr_translate_admin_reset_strings() {
    global $wpdb;

    // Confirm the strings table exists before clearing.
    $table = $wpdb->prefix . 'wpestate_translation_strings';
    $exists = ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) === $table );

    if ( ! $exists ) {
        return new WP_Error( 'wpr_translate_reset_missing', __( 'The translation strings table could not be found.', 'wpr-translate' ) );
    }

    // Remove all stored string entries.
    $deleted = $wpdb->query( "DELETE FROM {$table}" );

    if ( false === $deleted ) {
        return new WP_Error( 'wpr_translate_reset_failed', __( 'Failed to clear stored translation strings.', 'wpr-translate' ) );
    }

    // Clear cached scan state so subsequent scans run fully after a reset.
    delete_option( 'wpr_translate_scan_state' );

    return true;
}
