<?php
/**
 * Custom field rule helpers.
 */
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

require_once WPR_TRANSLATE_PATH . 'includes/custom-field-rules-storage.php';

/**
 * Get the rule file path.
 */
function wpr_translate_get_custom_field_rules_file_path() {
    // Build the default rules file path in the active theme.
    $path = trailingslashit( get_stylesheet_directory() ) . 'wpr/custom-fields-config.json';

    return apply_filters( 'wpr_translate_custom_field_rules_file', $path );
}

/**
 * Load rules from disk.
 */
function wpr_translate_read_custom_field_rules_file() {
    // Resolve the rules file path.
    $path = (string) wpr_translate_get_custom_field_rules_file_path();
    if ( '' === $path ) {
        return new WP_Error( 'wpr_cf_missing_path', __( 'The custom field rule file path is empty.', 'wpr-translate' ) );
    }
    if ( ! file_exists( $path ) ) {
        // Return an error when the rules file is missing.
        $error = new WP_Error( 'wpr_cf_missing_file', __( 'The custom field rule file could not be found.', 'wpr-translate' ) );
        $error->add_data( array( 'path' => $path ) );
        return $error;
    }
    $contents = file_get_contents( $path );
    if ( false === $contents ) {
        // Return an error when the file cannot be read.
        $error = new WP_Error( 'wpr_cf_unreadable', __( 'The custom field rule file is not readable.', 'wpr-translate' ) );
        $error->add_data( array( 'path' => $path ) );
        return $error;
    }
    $decoded = json_decode( $contents, true );
    if ( null === $decoded || ! is_array( $decoded ) ) {
        // Return an error for invalid JSON.
        $error = new WP_Error( 'wpr_cf_invalid_json', __( 'The custom field rule file contains invalid JSON.', 'wpr-translate' ) );
        $error->add_data( array( 'path' => $path ) );
        return $error;
    }
    // Normalize rule structures from the JSON payload.
    $raw_rules = isset( $decoded['custom_fields'] ) && is_array( $decoded['custom_fields'] ) ? $decoded['custom_fields'] : $decoded;
    $rules     = wpr_translate_normalize_custom_field_rules( $raw_rules );
    return array(
        'rules' => $rules,
        'hash'  => md5( $contents ),
        'path'  => $path,
    );
}

/**
 * Reset cached rule data.
 */
function wpr_translate_clear_custom_field_rules_cache() {
    // Remove cached rules and metadata from globals.
    unset( $GLOBALS['wpr_translate_cf_rules_cache'], $GLOBALS['wpr_translate_cf_rules_file'] );
}

/**
 * Get stored overrides.
 */
function wpr_translate_get_custom_field_overrides() {
    $stored = get_option( 'wpr_cf_rule_overrides', array() );

    if ( ! is_array( $stored ) ) {
        $stored = array();
    }

    // Sanitize override keys and actions.
    $sanitised = array();

    foreach ( $stored as $key => $value ) {
        $rule_key = sanitize_text_field( $key );
        $action   = sanitize_key( $value );

        if ( '' === $rule_key || '' === $action ) {
            continue;
        }

        $sanitised[ $rule_key ] = $action;
    }

    return $sanitised;
}

/**
 * Merge file defaults with overrides.
 */
function wpr_translate_get_custom_field_rules( $force_refresh = false ) {
    if ( $force_refresh ) {
        // Clear cache when refresh is requested.
        wpr_translate_clear_custom_field_rules_cache();
    }

    if ( isset( $GLOBALS['wpr_translate_cf_rules_cache'] ) ) {
        // Return cached rules when available.
        return $GLOBALS['wpr_translate_cf_rules_cache'];
    }

    $stored_defaults = wpr_translate_get_stored_custom_field_rules_defaults();

    if ( empty( $stored_defaults['rules'] ) ) {
        // Rule reload from file has been removed.
        $stored_defaults = wpr_translate_get_stored_custom_field_rules_defaults();
    }

    $defaults = isset( $stored_defaults['rules'] ) ? $stored_defaults['rules'] : array();
    $meta     = array(
        'hash'        => isset( $stored_defaults['hash'] ) ? (string) $stored_defaults['hash'] : '',
        'path'        => isset( $stored_defaults['path'] ) ? (string) $stored_defaults['path'] : wpr_translate_get_custom_field_rules_file_path(),
        'last_loaded' => isset( $stored_defaults['last_loaded'] ) ? absint( $stored_defaults['last_loaded'] ) : 0,
    );

    $overrides = wpr_translate_get_custom_field_overrides();
    $merged    = array();

    foreach ( $defaults as $id => $rule ) {
        // Preserve the file-provided action for reference.
        $rule['file_action'] = $rule['action'];
        $rule['source']      = 'file';

        if ( isset( $overrides[ $id ] ) ) {
            // Apply override action when present.
            $rule['action'] = $overrides[ $id ];
            $rule['source'] = 'override';
        }

        $merged[ $id ] = $rule;
    }

    foreach ( $overrides as $id => $action ) {
        if ( isset( $merged[ $id ] ) ) {
            continue;
        }

        // Add override-only rules that do not exist in defaults.
        $merged[ $id ] = array(
            'id'          => $id,
            'label'       => $id,
            'description' => '',
            'action'      => $action,
            'file_action' => '',
            'source'      => 'override',
        );
    }

    // Cache the merged rules and metadata for quick access.
    $GLOBALS['wpr_translate_cf_rules_cache'] = $merged;
    $GLOBALS['wpr_translate_cf_rules_file']  = $meta;

    return $merged;
}

/**
 * Save overrides and refresh cache.
 */
function wpr_translate_save_custom_field_overrides( $overrides ) {
    $allowed   = array( 'copy', 'translate', 'copy-once', 'ignore' );
    $sanitized = array();

    if ( is_array( $overrides ) ) {
        foreach ( $overrides as $key => $value ) {
            $rule_key   = sanitize_text_field( $key );
            $rule_value = sanitize_key( $value );

            if ( '' === $rule_key || '' === $rule_value ) {
                continue;
            }

            if ( ! in_array( $rule_value, $allowed, true ) ) {
                continue;
            }

            $sanitized[ $rule_key ] = $rule_value;
        }
    }

    // Persist overrides and refresh cached rules.
    update_option( 'wpr_cf_rule_overrides', $sanitized );
    wpr_translate_get_custom_field_rules( true );
}

/**
 * Store state about the last file load.
 */
function wpr_translate_store_custom_field_file_state( $state ) {
    // Normalize state values before storing.
    $state = wp_parse_args(
        is_array( $state ) ? $state : array(),
        array(
            'hash'          => '',
            'last_loaded'   => 0,
            'status'        => '',
            'path'          => wpr_translate_get_custom_field_rules_file_path(),
            'error_message' => '',
        )
    );
    $state['hash']          = sanitize_text_field( $state['hash'] );
    $state['status']        = sanitize_text_field( $state['status'] );
    $state['path']          = sanitize_text_field( $state['path'] );
    $state['error_message'] = sanitize_text_field( $state['error_message'] );
    $state['last_loaded']   = absint( $state['last_loaded'] );
    if ( 0 === $state['last_loaded'] ) {
        // Reuse the previous timestamp if available.
        $defaults = wpr_translate_get_stored_custom_field_rules_defaults();
        if ( ! empty( $defaults['last_loaded'] ) ) {
            $state['last_loaded'] = absint( $defaults['last_loaded'] );
        }
    }
    // Persist the file state.
    update_option( 'wpr_cf_file_state', $state );
}

/**
 * Reload rules from the JSON file and persist defaults.
 *
 * @return array|WP_Error
 */
function wpr_translate_reload_custom_field_rules_from_file() {
    // Read the rules file through the shared loader.
    $loaded = wpr_translate_read_custom_field_rules_file();
    if ( is_wp_error( $loaded ) ) {
        // Persist a readable error state for the admin screen.
        $error_data = $loaded->get_error_data();
        $error_path = is_array( $error_data ) && isset( $error_data['path'] ) ? sanitize_text_field( $error_data['path'] ) : wpr_translate_get_custom_field_rules_file_path();
        wpr_translate_store_custom_field_file_state(
            array(
                'status'        => 'error',
                'hash'          => '',
                'last_loaded'   => time(),
                'path'          => $error_path,
                'error_message' => $loaded->get_error_message(),
            )
        );
        return $loaded;
    }

    $rules     = isset( $loaded['rules'] ) && is_array( $loaded['rules'] ) ? $loaded['rules'] : array();
    $hash      = isset( $loaded['hash'] ) ? sanitize_text_field( (string) $loaded['hash'] ) : '';
    $path      = isset( $loaded['path'] ) ? sanitize_text_field( (string) $loaded['path'] ) : wpr_translate_get_custom_field_rules_file_path();
    $timestamp = time();

    // Merge legacy custom fields so older sites keep expected defaults.
    $custom_fields = function_exists( 'wpresidence_get_option' )
        ? wpresidence_get_option( 'wp_estate_custom_fields', '' )
        : get_option( 'wp_estate_custom_fields', '' );
    if ( ! is_array( $custom_fields ) ) {
        $custom_fields = maybe_unserialize( $custom_fields );
    }
    $legacy_rules = wpr_translate_convert_legacy_custom_fields_to_rules( $custom_fields );
    if ( ! empty( $legacy_rules ) ) {
        $rules = array_merge( $legacy_rules, $rules );
    }

    // Keep behavior consistent with file reload by resetting overrides.
    delete_option( 'wpr_cf_rule_overrides' );

    // Store defaults, refresh cache, and update file status metadata.
    wpr_translate_store_custom_field_rules_defaults( $rules, $hash, $path, $timestamp );
    wpr_translate_clear_custom_field_rules_cache();
    wpr_translate_store_custom_field_file_state(
        array(
            'status'        => 'loaded',
            'hash'          => $hash,
            'last_loaded'   => $timestamp,
            'path'          => $path,
            'error_message' => '',
        )
    );
    wpr_translate_get_custom_field_rules( true );

    return array(
        'rules' => $rules,
        'hash'  => $hash,
        'path'  => $path,
    );
}

/**
 * Describe the rules file state.
 */
function wpr_translate_get_custom_field_rules_state() {
    $state = get_option( 'wpr_cf_file_state', array() );
    if ( ! is_array( $state ) ) {
        $state = array();
    }
    // Fill defaults and sanitize stored state values.
    $state = wp_parse_args(
        $state,
        array(
            'hash'          => '',
            'last_loaded'   => 0,
            'status'        => '',
            'path'          => wpr_translate_get_custom_field_rules_file_path(),
            'error_message' => '',
        )
    );
    $state['hash']          = sanitize_text_field( $state['hash'] );
    $state['status']        = sanitize_text_field( $state['status'] );
    $state['path']          = sanitize_text_field( $state['path'] );
    $state['error_message'] = sanitize_text_field( $state['error_message'] );
    $state['last_loaded']   = absint( $state['last_loaded'] );
    if ( 0 === $state['last_loaded'] ) {
        // Fall back to default stored timestamp.
        $defaults = wpr_translate_get_stored_custom_field_rules_defaults();
        if ( ! empty( $defaults['last_loaded'] ) ) {
            $state['last_loaded'] = absint( $defaults['last_loaded'] );
        }
    }
    // Compute current file hash when file exists.
    $state['file_exists']   = file_exists( $state['path'] );
    $hash                   = '';
    if ( $state['file_exists'] ) {
        $computed = @md5_file( $state['path'] ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
        if ( false !== $computed ) {
            $hash = (string) $computed;
        }
    }
    $state['current_hash'] = $hash;
    return $state;
}
