<?php
/**
 * Actions handling admin post list translation operations.
 *
 * @package WPR_Translate
 */

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

/**
 * Handles the Add Translation action triggered from the posts table.
 */
function wpr_translation_handle_add_translation_request() {
    // Read request parameters from the query string.
    $post_id  = isset( $_GET['post_id'] ) ? absint( $_GET['post_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    $language = isset( $_GET['language'] ) ? sanitize_text_field( wp_unslash( $_GET['language'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

    if ( ! $post_id || '' === $language ) {
        // Stop when required inputs are missing.
        wp_die( esc_html__( 'Invalid translation request.', 'wpr-translate' ) );
    }

    // Validate the nonce tied to this post/language action.
    $nonce_action = wpr_translation_get_translation_nonce_action( $post_id, $language );

    check_admin_referer( $nonce_action );

    // Create or reuse the translation draft.
    $new_post_id = wpr_translation_create_translation_draft( $post_id, $language );

    if ( is_wp_error( $new_post_id ) ) {
        wp_die( esc_html( $new_post_id->get_error_message() ) );
    }

    // Redirect directly to the translation editor.
    wp_safe_redirect( get_edit_post_link( $new_post_id, 'raw' ) );
    exit;
}

/**
 * Create or fetch a translation draft for the requested language.
 *
 * @param int    $post_id  Source post ID.
 * @param string $language Target language code.
 *
 * @return int|WP_Error Translation post ID or WP_Error on failure.
 */
function wpr_translation_create_translation_draft( $post_id, $language ) {
    // Normalize inputs.
    $post_id  = absint( $post_id );
    $language = strtolower( sanitize_text_field( $language ) );

    if ( ! $post_id || '' === $language ) {
        // Invalid input parameters.
        return new WP_Error( 'wpr_translate_invalid_request', __( 'Invalid translation request.', 'wpr-translate' ) );
    }

    if ( ! current_user_can( 'edit_post', $post_id ) ) {
        // Permission check for the source post.
        return new WP_Error( 'wpr_translate_permission', __( 'You are not allowed to clone this post.', 'wpr-translate' ) );
    }

    // Load the source post.
    $source_post = get_post( $post_id );

    // Track the source post ID for cloning operations; defaults to the current post ID.
    $source_post_id = $post_id;

    if ( ! $source_post ) {
        // Source post must exist.
        return new WP_Error( 'wpr_translate_source_missing', __( 'Source post not found.', 'wpr-translate' ) );
    }

    $languages = wpr_translation_get_active_languages();

    if ( empty( $languages ) ) {
        // No languages configured means no translation can be created.
        return new WP_Error( 'wpr_translate_no_languages', __( 'No languages available for translation.', 'wpr-translate' ) );
    }

    // Normalize the requested language identifier to a configured code.
    if ( function_exists( 'wpr_translate_get_language' ) ) {
        $language_payload = wpr_translate_get_language( $language );

        if ( is_array( $language_payload ) && ! empty( $language_payload['code'] ) ) {
            $language = (string) $language_payload['code'];
        }
    }

    $language_codes = wp_list_pluck( $languages, 'code' );

    if ( ! in_array( $language, $language_codes, true ) ) {
        // Ensure the target language is valid.
        return new WP_Error( 'wpr_translate_invalid_language', __( 'Invalid target language.', 'wpr-translate' ) );
    }

    $element_type = wpr_translation_get_element_type( $source_post->post_type );
    $translations = wpr_translation_get_translation_group( $post_id, $element_type );
    $existing_translations = array_filter(
        $translations['translations'],
        'wpr_translation_is_translation_post_available'
    );
    $default_language = sanitize_key( wpr_translation_get_default_language_code( $languages ) );
    $trid             = isset( $translations['trid'] ) ? absint( $translations['trid'] ) : 0;
    $source_language  = isset( $translations['source_language'] ) ? sanitize_key( $translations['source_language'] ) : '';

    if ( '' !== $source_language ) {
        $source_language = strtolower( $source_language );
    }

    if ( '' !== $default_language ) {
        $default_language = strtolower( $default_language );
    }

    if ( $source_language && isset( $translations['translations'][ $source_language ] ) ) {
        $source_post_id = (int) $translations['translations'][ $source_language ];
    } elseif ( $default_language && isset( $translations['translations'][ $default_language ] ) ) {
        $source_post_id = (int) $translations['translations'][ $default_language ];
    }


    if ( isset( $existing_translations[ $language ] ) ) {
        $existing_id = (int) $existing_translations[ $language ];



        if ( ! current_user_can( 'edit_post', $existing_id ) ) {
            // Require permission for existing translation.
            return new WP_Error( 'wpr_translate_permission', __( 'You are not allowed to update this translation.', 'wpr-translate' ) );
        }

        $existing_post = get_post( $existing_id );


        if ( $existing_post ) {
            // Update the existing translation before returning it.
            $page_template = wpr_translation_get_validated_page_template( $source_post );

            $update_result = wp_update_post(
                array(
                    'ID'                   => $existing_id,
                    'post_title'           => $source_post->post_title,
                    'post_content'         => $source_post->post_content,
                    'post_excerpt'         => $source_post->post_excerpt,
                    'post_parent'          => $source_post->post_parent,
                    'menu_order'           => $source_post->menu_order,
                    'comment_status'       => $source_post->comment_status,
                    'ping_status'          => $source_post->ping_status,
                    'post_password'        => $source_post->post_password,
                    'post_content_filtered' => $source_post->post_content_filtered,
                ),
                true
            );

            update_post_meta( $existing_id, '_wp_page_template', $page_template );

            // Sync related meta, attachments, and taxonomies.
            wpr_translation_clone_meta_fields( $source_post_id, $existing_id );
            wpr_translation_clone_attachments( $source_post_id, $existing_id );
            wpr_translation_clone_taxonomies( $source_post_id, $existing_id, $source_post->post_type, $language );

            // Store the translated language code on the translation post.
            update_post_meta( $existing_id, 'wpr_translated_language', sanitize_key( $language ) );
            update_post_meta( $existing_id, 'wpr_translated_original_post_id', absint( $source_post_id ) );

            if ( $trid > 0 ) {
                update_post_meta( $existing_id, 'wpr_translated_trid', $trid );
            }

            return $existing_id;
        }

    }

    $source_post = get_post( $source_post_id );

    if ( ! $source_post ) {
        // Source post must exist.
        return new WP_Error( 'wpr_translate_source_missing', __( 'Source post not found.', 'wpr-translate' ) );
    }

    if ( ! $trid ) {
        // Create a translation group when missing.
        $trid = wpr_translation_generate_trid();

        if ( ! $source_language ) {
            $source_language = $default_language;
        }

        wpr_translation_insert_translation_record(
            $post_id,
            $element_type,
            $trid,
            $source_language,
            null,
            $source_post->post_status,
            true
        );
    }

    if ( ! $source_language ) {
        // Default the source language when missing.
        $source_language = $default_language;
    }

    // Determine the correct template to apply to the draft.
    $page_template = wpr_translation_get_validated_page_template( $source_post );

    // Create the draft translation post.
    $new_post_id = wp_insert_post(
        array(
            'post_type'             => $source_post->post_type,
            'post_status'           => 'draft',
            'post_title'            => $source_post->post_title,
            'post_content'          => $source_post->post_content,
            'post_excerpt'          => $source_post->post_excerpt,
            'post_author'           => get_current_user_id(),
            'comment_status'        => $source_post->comment_status,
            'ping_status'           => $source_post->ping_status,
            'menu_order'            => $source_post->menu_order,
            'post_parent'           => $source_post->post_parent,
            'post_password'         => $source_post->post_password,
            'post_content_filtered' => $source_post->post_content_filtered,
        ),
        true
    );

    if ( is_wp_error( $new_post_id ) ) {
        return $new_post_id;
    }

    // Persist template and clone additional data.
    update_post_meta( $new_post_id, '_wp_page_template', $page_template );

    wpr_translation_clone_meta_fields( $source_post_id, $new_post_id );
    wpr_translation_clone_attachments( $source_post_id, $new_post_id );
    wpr_translation_clone_taxonomies( $source_post_id, $new_post_id, $source_post->post_type, $language );

    // Store the translated language code on the new translation draft.
    update_post_meta( $new_post_id, 'wpr_translated_language', sanitize_key( $language ) );
    update_post_meta( $new_post_id, 'wpr_translated_original_post_id', absint( $source_post_id ) );

    if ( $trid > 0 ) {
        update_post_meta( $new_post_id, 'wpr_translated_trid', $trid );
    }

    wpr_translation_insert_translation_record(
        $new_post_id,
        $element_type,
        $trid,
        $language,
        $source_language,
        'draft',
        false
    );


    return $new_post_id;
}

/**
 * Resolve a safe page template for the new draft to prevent invalid template errors.
 *
 * @param WP_Post $source_post Source post object.
 *
 * @return string
 */
function wpr_translation_get_validated_page_template( $source_post ) {
    if ( ! $source_post instanceof WP_Post ) {
        // Default to the standard template.
        return 'default';
    }

    if ( 'page' !== $source_post->post_type ) {
        // Only pages use templates.
        return '';
    }

    $template = get_page_template_slug( $source_post->ID );

    if ( '' === $template ) {
        // Fall back to the stored page template meta.
        $template = get_post_meta( $source_post->ID, '_wp_page_template', true );
    }

    $template = is_string( $template ) ? sanitize_text_field( $template ) : '';

    if ( '' === $template || 'default' === $template ) {
        return 'default';
    }

    return $template;
}
add_action( 'admin_action_wpr_add_translation', 'wpr_translation_handle_add_translation_request' );

/**
 * Clones attachments from the source post to the translated post.
 *
 * @param int $source_post_id Source post ID.
 * @param int $new_post_id    New post ID.
 */
function wpr_translation_clone_attachments( $source_post_id, $new_post_id ) {
    // Read settings to determine whether media should sync.
    $settings   = get_option( 'wpr_translate_settings', array() );
    $sync_media = ! empty( $settings['sync_media'] );

    if ( ! $sync_media ) {
        // Exit when media sync is disabled.
        return;
    }

    $source_post_id = absint( $source_post_id );
    $new_post_id    = absint( $new_post_id );

    if ( ! $source_post_id || ! $new_post_id ) {
        // Invalid IDs mean no work.
        return;
    }

    $arguments = array(
        'numberposts'      => -1,
        'post_type'        => 'attachment',
        'post_parent'      => $source_post_id,
        'post_status'      => null,
        'orderby'          => 'menu_order',
        'post_mime_type'   => 'image',
        'order'            => 'ASC',
        'fields'           => 'ids',
        'suppress_filters' => false,
    );

    $attachment_ids = get_posts( $arguments );

    if ( empty( $attachment_ids ) ) {
        // No attachments to clone.
        return;
    }

    foreach ( $attachment_ids as $attachment_id ) {
        $attachment_id = absint( $attachment_id );

        if ( $attachment_id <= 0 ) {
            continue;
        }

        $attachment = get_post( $attachment_id );

        if ( ! $attachment ) {
            continue;
        }

        $attached_file = get_attached_file( $attachment_id );

        if ( empty( $attached_file ) ) {
            continue;
        }

        $new_attachment_id = wp_insert_attachment(
            array(
                'post_title'     => $attachment->post_title,
                'post_content'   => $attachment->post_content,
                'post_excerpt'   => $attachment->post_excerpt,
                'post_status'    => 'inherit',
                'post_mime_type' => $attachment->post_mime_type,
                'post_parent'    => $new_post_id,
                'post_author'    => get_current_user_id(),
                'menu_order'     => $attachment->menu_order,
            ),
            $attached_file,
            $new_post_id,
            true
        );

        if ( is_wp_error( $new_attachment_id ) ) {
            continue;
        }

        $meta = get_post_meta( $attachment_id );

        if ( ! empty( $meta ) ) {
            // Copy attachment metadata excluding editor locks.
            foreach ( $meta as $meta_key => $values ) {
                if ( in_array( $meta_key, array( '_edit_lock', '_edit_last', '_wp_attachment_metadata' ), true ) ) {
                    continue;
                }

                delete_post_meta( $new_attachment_id, $meta_key );

                foreach ( $values as $value ) {
                    add_post_meta( $new_attachment_id, $meta_key, maybe_unserialize( $value ) );
                }
            }
        }

        $metadata = wp_get_attachment_metadata( $attachment_id );

        if ( ! empty( $metadata ) ) {
            // Copy image metadata for the attachment.
            wp_update_attachment_metadata( $new_attachment_id, $metadata );
        }

        $relative_path = get_post_meta( $attachment_id, '_wp_attached_file', true );

        if ( ! empty( $relative_path ) ) {
            // Preserve the relative file path.
            update_post_meta( $new_attachment_id, '_wp_attached_file', $relative_path );
        }
    }
}

/**
 * Clones taxonomy relationships from the source post to the new post.
 *
 * @param int    $source_post_id  Source post ID.
 * @param int    $new_post_id     New post ID.
 * @param string $post_type       Post type.
 * @param string $target_language Target language code.
 */
function wpr_translation_clone_taxonomies( $source_post_id, $new_post_id, $post_type, $target_language ) {
    // Normalize the target language code.
    $target_language = strtolower( sanitize_key( $target_language ) );
    $languages       = wpr_translation_get_active_languages();
    $default_language = strtolower( sanitize_key( wpr_translation_get_default_language_code( $languages ) ) );

    $taxonomies = get_object_taxonomies( $post_type );

    if ( empty( $taxonomies ) ) {
        // No taxonomies to copy.
        return;
    }

    foreach ( $taxonomies as $taxonomy ) {
        $term_ids = wp_get_object_terms(
            $source_post_id,
            $taxonomy,
            array(
                'fields' => 'ids',
            )
        );

        if ( is_wp_error( $term_ids ) || empty( $term_ids ) ) {
            continue;
        }

        if ( ! wpr_translation_is_taxonomy_translatable( $taxonomy ) ) {
            // Copy terms directly when taxonomy is not translatable.
            wp_set_object_terms( $new_post_id, array_unique( array_map( 'intval', $term_ids ) ), $taxonomy );
            continue;
        }

        $translated_term_ids = array();

        foreach ( $term_ids as $term_id ) {
            $term_id = (int) $term_id;

            if ( $term_id <= 0 ) {
                continue;
            }

            $canonical_term_id = $term_id;

            if ( function_exists( 'wpr_translate_resolve_original_term_id' ) ) {
                $resolved_canonical = absint( wpr_translate_resolve_original_term_id( $term_id, $taxonomy ) );

                if ( $resolved_canonical > 0 ) {
                    $canonical_term_id = $resolved_canonical;
                }
            }

            $translated_id = $canonical_term_id;

            if ( '' !== $target_language && $target_language !== $default_language ) {
                $translated_id = 0;

                if ( function_exists( 'wpr_translate_lookup_translated_term_id_strict' ) ) {
                    $strict_target = wpr_translate_lookup_translated_term_id_strict( $canonical_term_id, $taxonomy, $target_language );

                    if ( is_numeric( $strict_target ) ) {
                        $strict_target = (int) $strict_target;

                        // Ignore invalid self-mappings and force proper resolution.
                        if ( $strict_target > 0 && $strict_target !== $canonical_term_id ) {
                            $translated_id = $strict_target;
                        }
                    }
                }

                if (
                    $translated_id <= 0
                    && wpr_translation_is_taxonomy_auto_duplicate_enabled( $taxonomy )
                    && function_exists( 'wpr_translation_duplicate_term_for_language' )
                ) {
                    // Auto-create missing term translations when configured.
                    wpr_translation_duplicate_term_for_language( $canonical_term_id, $taxonomy, $target_language, array() );

                    if ( function_exists( 'wpr_translate_lookup_translated_term_id_strict' ) ) {
                        $strict_target = wpr_translate_lookup_translated_term_id_strict( $canonical_term_id, $taxonomy, $target_language );

                        if ( is_numeric( $strict_target ) ) {
                            $translated_id = (int) $strict_target;
                        }
                    }
                }
            }

            if ( $translated_id > 0 ) {
                $translated_term_ids[] = $translated_id;
            }
        }

        if ( empty( $translated_term_ids ) ) {
            continue;
        }

        // Assign translated term IDs to the new post.
        wp_set_object_terms( $new_post_id, array_unique( $translated_term_ids ), $taxonomy );
    }
}

/**
 * Helper that inserts or updates a translation record.
 *
 * The routine now updates existing rows when necessary so integrations can safely call it without
 * worrying about duplicate entries for the same element.
 *
 * @param int         $post_id         Post ID being inserted.
 * @param string      $element_type    Element type key.
 * @param int         $trid            Translation group ID.
 * @param string      $language_code   Language code for the post.
 * @param string|null $source_language Source language code.
 * @param string      $post_status     Post status.
 * @param bool        $original        Whether the record is the original.
 */
function wpr_translation_insert_translation_record( $post_id, $element_type, $trid, $language_code, $source_language, $post_status, $original ) {
    global $wpdb;

    // Normalize all inputs before writing to the database.
    $post_id        = absint( $post_id );
    $trid           = absint( $trid );
    $element_type   = sanitize_key( $element_type );
    $language_code  = strtolower( sanitize_key( $language_code ) );
    $post_status    = sanitize_key( $post_status );
    $source_language = is_string( $source_language ) ? strtolower( sanitize_key( $source_language ) ) : '';

    if ( $post_id <= 0 || $trid <= 0 || '' === $element_type || '' === $language_code ) {
        // Required fields missing.
        return;
    }

    $table = $wpdb->prefix . 'wpestate_translation_translations';

    // Check for an existing translation record.
    $existing = $wpdb->get_row(
        $wpdb->prepare(
            "SELECT translation_id FROM {$table} WHERE element_id = %d AND element_type = %s LIMIT 1",
            $post_id,
            $element_type
        ),
        ARRAY_A
    );

    $resolved_source_language = $source_language;

    if ( '' === $resolved_source_language ) {
        // Use the language code as a fallback source.
        $resolved_source_language = $language_code;
    }

    $data = array(
        'element_type'         => $element_type,
        'element_id'           => $post_id,
        'trid'                 => $trid,
        'language_code'        => $language_code,
        'source_language_code' => $resolved_source_language,
        'post_status'          => ( '' === $post_status ) ? 'publish' : $post_status,
        'translator_id'        => get_current_user_id(),
        'original'             => $original ? 1 : 0,
        'needs_update'         => 0,
    );

    $formats = array( '%s', '%d', '%d', '%s', '%s', '%s', '%d', '%d', '%d' );

    $inserted_new = false;

    if ( $existing ) {
        // Update the existing translation record.
        $wpdb->update(
            $table,
            $data,
            array( 'translation_id' => (int) $existing['translation_id'] ),
            $formats,
            array( '%d' )
        );
    } else {
        // Insert a new translation record.
        $wpdb->insert( $table, $data, $formats );
        $inserted_new = true;
    }

    if ( $original ) {
        // Ensure only one record is marked as original.
        $wpdb->query(
            $wpdb->prepare(
                "UPDATE {$table} SET original = 0, source_language_code = %s WHERE trid = %d AND element_type = %s AND element_id <> %d",
                $language_code,
                $trid,
                $element_type,
                $post_id
            )
        );
    }

    if ( $inserted_new ) {
        /**
         * Fires after a translation record has been created.
         *
         * @param int         $post_id         Post ID associated with the translation record.
         * @param string      $element_type    Element type key.
         * @param int         $trid            Translation group identifier.
         * @param string      $language_code   Language code of the translation.
         * @param string|null $source_language Source language code.
         * @param string      $post_status     Post status stored in the translation table.
         * @param bool        $original        Whether the entry represents the original post.
         */
        do_action( 'wpr_translation_created', $post_id, $element_type, $trid, $language_code, $source_language, $post_status, $original );
    }
}
