<?php
/**
 * Synchronizes nav menu translation relationships.
 *
 * @package WPR_Translate
 */

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

if ( ! function_exists( 'wpr_translation_get_nav_menu_translation_trid' ) ) {
    /**
     * Retrieves the translation group identifier for a nav menu.
     *
     * @param int $menu_id Menu identifier.
     *
     * @return int
     */
    function wpr_translation_get_nav_menu_translation_trid( $menu_id ) {
        global $wpdb;

        // Normalize the menu ID.
        $menu_id = absint( $menu_id );

        if ( $menu_id <= 0 ) {
            // No valid menu ID means no translation group.
            return 0;
        }

        // Query the translation group ID for this menu.
        $table = $wpdb->prefix . 'wpestate_translation_translations';

        return (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT trid FROM {$table} WHERE element_id = %d AND element_type = %s LIMIT 1",
                $menu_id,
                'tax_nav_menu'
            )
        );
    }
}

if ( ! function_exists( 'wpr_translation_upsert_nav_menu_translation' ) ) {
    /**
     * Inserts or updates a nav menu translation record.
     *
     * @param int    $menu_id        Menu identifier.
     * @param string $language_code  Language code for the menu.
     * @param int    $trid           Translation group identifier.
     * @param string $source_language Source language code.
     * @param bool   $is_original    Whether the menu is the original.
     */
    function wpr_translation_upsert_nav_menu_translation( $menu_id, $language_code, $trid, $source_language, $is_original ) {
        global $wpdb;

        // Normalize inputs.
        $menu_id        = absint( $menu_id );
        $trid           = absint( $trid );
        $language_code  = strtolower( sanitize_key( $language_code ) );
        $source_language = strtolower( sanitize_key( $source_language ) );

        if ( $menu_id <= 0 || $trid <= 0 || '' === $language_code ) {
            // Required values missing.
            return;
        }

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

        $data = array(
            'element_type'         => 'tax_nav_menu',
            'element_id'           => $menu_id,
            'trid'                 => $trid,
            'language_code'        => $language_code,
            'source_language_code' => ( $is_original || '' === $source_language ) ? null : $source_language,
            'post_status'          => 'publish',
            'translator_id'        => get_current_user_id(),
            'original'             => $is_original ? 1 : 0,
        );

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

        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 );
        }

        if ( $is_original ) {
            // Ensure only one menu is marked as original per group.
            $wpdb->query(
                $wpdb->prepare(
                    "UPDATE {$table} SET original = 0 WHERE trid = %d AND element_type = %s AND element_id <> %d",
                    $trid,
                    'tax_nav_menu',
                    $menu_id
                )
            );
        }
    }
}

if ( ! function_exists( 'wpr_translation_ensure_nav_menu_translation_record' ) ) {
    /**
     * Ensures a nav menu has a translation record when assigned a language.
     *
     * @param int    $menu_id       Menu identifier.
     * @param string $language_code Language code.
     */
    function wpr_translation_ensure_nav_menu_translation_record( $menu_id, $language_code ) {
        $menu_id       = absint( $menu_id );
        $language_code = strtolower( sanitize_key( $language_code ) );

        if ( $menu_id <= 0 || '' === $language_code ) {
            // Cannot create a record without a menu and language.
            return;
        }

        $trid = wpr_translation_get_nav_menu_translation_trid( $menu_id );

        if ( ! $trid && function_exists( 'wpr_translation_generate_trid' ) ) {
            // Generate a translation group when missing.
            $trid = wpr_translation_generate_trid();
        }

        if ( ! $trid ) {
            // Abort if no translation group is available.
            return;
        }

        // Determine the default language and whether this is the original.
        $overview     = wpr_translation_get_nav_menu_overview();
        $default_code = isset( $overview['default'] ) ? strtolower( sanitize_key( $overview['default'] ) ) : '';
        $is_original  = ( '' !== $default_code && $language_code === $default_code );
        $source_lang  = $is_original ? '' : $default_code;

        wpr_translation_upsert_nav_menu_translation(
            $menu_id,
            $language_code,
            $trid,
            $is_original ? '' : $source_lang,
            $is_original
        );
    }
}

if ( ! function_exists( 'wpr_translation_sync_nav_menu_translations_from_locations' ) ) {
    /**
     * Aligns nav menu translation groups based on location assignments.
     *
     * @param array<string, array<string, int>> $locations Location assignments grouped by language.
     */
    function wpr_translation_sync_nav_menu_translations_from_locations( $locations ) {
        if ( empty( $locations ) || ! is_array( $locations ) ) {
            // Nothing to sync.
            return;
        }

        // Use the default language as the source when possible.
        $overview     = wpr_translation_get_nav_menu_overview();
        $default_code = isset( $overview['default'] ) ? strtolower( sanitize_key( $overview['default'] ) ) : '';

        foreach ( $locations as $language_map ) {
            if ( ! is_array( $language_map ) || empty( $language_map ) ) {
                continue;
            }

            $normalized = array();

            foreach ( $language_map as $code => $menu_id ) {
                $lang    = strtolower( sanitize_key( $code ) );
                $menu_id = absint( $menu_id );

                if ( '' === $lang || $menu_id <= 0 ) {
                    // Skip invalid assignments.
                    continue;
                }

                $normalized[ $lang ] = $menu_id;
            }

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

            $source_language = '';
            $source_menu_id  = 0;

            if ( '' !== $default_code && isset( $normalized[ $default_code ] ) ) {
                // Prefer the default language assignment as the source.
                $source_language = $default_code;
                $source_menu_id  = $normalized[ $default_code ];
            } else {
                foreach ( $normalized as $lang => $menu_id ) {
                    // Fall back to the first available language.
                    $source_language = $lang;
                    $source_menu_id  = $menu_id;
                    break;
                }
            }

            if ( $source_menu_id <= 0 ) {
                // No source menu means no sync work.
                continue;
            }

            $trid = wpr_translation_get_nav_menu_translation_trid( $source_menu_id );

            if ( ! $trid ) {
                // Try to reuse any existing translation group in the map.
                foreach ( $normalized as $menu_id ) {
                    $trid = wpr_translation_get_nav_menu_translation_trid( $menu_id );

                    if ( $trid ) {
                        break;
                    }
                }
            }

            if ( ! $trid && function_exists( 'wpr_translation_generate_trid' ) ) {
                // Generate a translation group when none exists.
                $trid = wpr_translation_generate_trid();
            }

            if ( ! $trid ) {
                // Abort when no translation group is available.
                continue;
            }

            foreach ( $normalized as $lang => $menu_id ) {
                // Upsert translation records for each language/menu pair.
                $is_original = ( $lang === $source_language );
                $source_lang = $is_original ? '' : $source_language;

                wpr_translation_upsert_nav_menu_translation( $menu_id, $lang, $trid, $source_lang, $is_original );
            }
        }
    }
}
