<?php

/**
 * Migration 0017 — Merge Scene Root into page-level Scene
 *
 * Retires the special "Scene Root" section concept. Scene Root was always
 * just a regular `section` element flagged with `is_scene_root: true` that
 * held page-wide background + overlay settings. Splitting "the scene" into
 * a real page concept and a phantom-section concept created the duplicate
 * "scene vs scene root" confusion users complained about.
 *
 * For each page that has a Scene Root section in its element_tree:
 *   1. Lift its background + per-section gradient overlay settings (and
 *      their per-device variants) onto the page's pageSettings JSON. Only
 *      copy keys the page doesn't already have a non-empty value for.
 *   2. Reparent any direct children of Scene Root to the top level
 *      (parent_id = null) so they remain in the page in their existing
 *      visual order. Static layer effectively becomes top-level page
 *      content.
 *   3. Delete the Scene Root element node from the element_tree.
 *   4. Re-encode and write both columns back.
 *
 * Idempotent: pages with no `is_scene_root` flag are skipped untouched. So
 * pages already migrated, or never having a Scene Root, are no-ops.
 *
 * The internal `screen_*` pageSettings keys (screen_mode, screen_gradient_*,
 * screen_cloud_effect, etc.) are NOT renamed in this migration — that's a
 * separate follow-up ship that can run independently.
 *
 * @since 2.0.902
 */

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

return [
    'description' => 'Merge Scene Root section into page-level Scene (lift settings, flatten tree)',

    // No schema change.
    'up' => [],

    // Data migration: rewrite elements + settings JSON for every page.
    'php' => function () {
        $table = \Instinctor\Core\DB::prefix() . 'instinctor_pages';

        // Keys lifted from Scene Root section settings → pageSettings.
        // Only copied if the page doesn't already hold a non-empty value.
        $liftKeys = [
            'bg_color',
            'bg_image',
            'bg_image_position',
            'bg_image_size',
            'bg_fixed',
            'bg_video',
            'bg_video_fallback',
            'bg_animation_enabled',
            'bg_animation_layers',
            'animation_layers',
        ];
        // The legacy per-section gradient overlay maps to the page-level
        // screen_gradient_* keys (already-relocated page overlay UI).
        // Only copy if the page-level overlay isn't already configured.
        $overlayMap = [
            'gradient_overlay_shape'  => 'screen_gradient_shape',
            'gradient_overlay_color1' => 'screen_gradient_color1',
            'gradient_overlay_color2' => 'screen_gradient_color2',
        ];
        $devices  = ['', '_tablet', '_mobile'];

        $rows = \Instinctor\Core\DB::get_results(
            "SELECT id, elements, settings FROM {$table}",
            'ARRAY_A'
        );
        if (empty($rows)) {
            return;
        }

        $touched   = 0;
        $rootCount = 0;

        foreach ($rows as $row) {
            $pageId   = (int) $row['id'];
            $elements = json_decode((string) $row['elements'], true);
            $settings = json_decode((string) $row['settings'], true);

            if (!is_array($elements)) $elements = [];
            if (!is_array($settings)) $settings = [];

            // Find the Scene Root element (if any). Always at the top level
            // by convention; flag is in its settings sub-array.
            $rootIdx = null;
            $rootEl  = null;
            foreach ($elements as $i => $el) {
                if (!is_array($el)) continue;
                $sub = is_array($el['settings'] ?? null) ? $el['settings'] : [];
                if (!empty($sub['is_scene_root'])) {
                    $rootIdx = $i;
                    $rootEl  = $el;
                    break;
                }
            }

            if ($rootIdx === null) {
                // Nothing to do — scrub any defensive `is_scene_root` flag
                // that might be lingering on non-root elements (defensive).
                continue;
            }

            $rootCount++;

            $rootSub = is_array($rootEl['settings'] ?? null) ? $rootEl['settings'] : [];
            $rootId  = $rootEl['id'] ?? null;

            // ── 1. Lift settings → pageSettings ──────────────────────────
            // Background + animation: copy each key (and its _tablet / _mobile
            // variants) only if the page doesn't already have a non-empty value.
            foreach ($liftKeys as $base) {
                foreach ($devices as $suf) {
                    $k = $base . $suf;
                    if (!array_key_exists($k, $rootSub)) continue;
                    if (isset($settings[$k]) && $settings[$k] !== '' && $settings[$k] !== null) continue;
                    $settings[$k] = $rootSub[$k];
                }
            }

            // Gradient overlay: only copy if the page-level overlay isn't
            // already configured (matches the user's most recent intent).
            $pageHasOverlay = !empty($settings['screen_gradient_shape']);
            if (!$pageHasOverlay) {
                foreach ($overlayMap as $srcBase => $dstBase) {
                    foreach ($devices as $suf) {
                        $sk = $srcBase . $suf;
                        $dk = $dstBase . $suf;
                        if (!array_key_exists($sk, $rootSub)) continue;
                        if (isset($settings[$dk]) && $settings[$dk] !== '' && $settings[$dk] !== null) continue;
                        $settings[$dk] = $rootSub[$sk];
                    }
                }
            }

            // ── 2. Reparent direct children → top-level ─────────────────
            // Children that pointed at the Scene Root's id now point at NULL.
            // Visual order preserved — children stay in their existing array
            // positions; we only flip their parent_id reference.
            if ($rootId !== null) {
                foreach ($elements as $i => $el) {
                    if (!is_array($el)) continue;
                    if (($el['parent_id'] ?? null) == $rootId) {
                        $elements[$i]['parent_id'] = null;
                    }
                }
            }

            // ── 3. Drop the Scene Root element ───────────────────────────
            unset($elements[$rootIdx]);
            $elements = array_values($elements);

            // ── 4. Defensive: strip is_scene_root anywhere it lingers ───
            // (Only Scene Root should have had it, but historical data is
            // never as clean as the spec.)
            foreach ($elements as $i => $el) {
                if (!is_array($el)) continue;
                $sub = is_array($el['settings'] ?? null) ? $el['settings'] : [];
                if (array_key_exists('is_scene_root', $sub)) {
                    unset($sub['is_scene_root']);
                    $elements[$i]['settings'] = $sub;
                }
            }

            // ── 5. Write back ────────────────────────────────────────────
            $ok = \Instinctor\Core\DB::update(
                $table,
                [
                    'elements' => json_encode($elements, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
                    'settings' => json_encode($settings, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
                ],
                ['id' => $pageId]
            );
            if ($ok !== false) {
                $touched++;
            }
        }

        // Log so the deploy log shows what happened.
        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
        error_log(sprintf(
            '[Instinctor 0017] Scene Root merge: %d page(s) had a Scene Root, %d row(s) updated.',
            $rootCount,
            $touched
        ));
    },

    // No down-migration: the merge flattens structure. Restoring is_scene_root
    // and re-nesting children would require knowing which children were inside
    // which Scene Root, which we no longer track. Roll back from a backup if
    // needed.
    'down' => [],
];
