<?php

/**
 * Migration 0021 — Convert legacy storyboard_frame elements to section
 *
 * Storyboard frames were originally implemented as their own element type
 * (`storyboard_frame`). After dogfooding it became clear that frames want
 * every section feature — dropzones, animation layers, mesh gradients,
 * padding control, structure-tree entries — and reimplementing all of
 * that on a parallel type was waste. Decision (2.1.445): frames ARE
 * sections. The storyboard parent just orchestrates scroll progress;
 * each frame is a section nested as its child.
 *
 * This migration rewrites all rows in `instinctor_pages` to change any
 * top-level element of type `storyboard_frame` (where parent_id is a
 * storyboard) to type `section`, preserving every existing setting
 * (length_vh, transition, and whatever the designer had added).
 *
 * Idempotent — if no `storyboard_frame` elements exist, the migration
 * is a no-op and logs that fact.
 *
 * @since 2.1.445
 */

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

return [
    'description' => 'Convert legacy storyboard_frame elements to section type (frames are now sections)',

    'up' => [],

    'php' => function () {
        $table = \Instinctor\Core\DB::prefix() . 'instinctor_pages';
        $rows  = \Instinctor\Core\DB::get_results(
            "SELECT id FROM {$table} ORDER BY id ASC",
            ARRAY_A
        );
        if (!is_array($rows) || empty($rows)) {
            // phpcs:disable WordPress.PHP.DevelopmentFunctions -- server-side error capture / one-time migration logging, not debug output.
            error_log('[Instinctor migration 0021] No pages to scan.');
            // phpcs:enable WordPress.PHP.DevelopmentFunctions
            return;
        }

        $converted = 0;
        $pages     = 0;
        foreach ($rows as $row) {
            $pageId = (int) ($row['id'] ?? 0);
            if (!$pageId) continue;

            // Read raw elements blob directly (bypassing PageService::getElements
            // so the normaliser doesn't strip the legacy type before we get to
            // process it). PageService::ALLOWED_ELEMENT_TYPES still includes
            // `storyboard_frame` for the duration of this migration.
            $jsonRow = \Instinctor\Core\DB::get_row(
                \Instinctor\Core\DB::prepare(
                    "SELECT elements FROM {$table} WHERE id = %d LIMIT 1",
                    $pageId
                ),
                ARRAY_A
            );
            if (!$jsonRow) continue;
            $json = $jsonRow['elements'] ?? '';
            if (!$json) continue;

            $tree = json_decode($json, true);
            if (!is_array($tree)) continue;

            $pageChanged = false;
            foreach ($tree as &$el) {
                if (!is_array($el)) continue;
                if (($el['type'] ?? '') === 'storyboard_frame') {
                    $el['type'] = 'section';
                    // Make sure a few section essentials exist so the
                    // converted frame renders with sensible defaults
                    // (background, alignment) rather than collapsing.
                    if (!isset($el['settings']) || !is_array($el['settings'])) $el['settings'] = [];
                    $defaults = [
                        'bg_color'      => 'transparent',
                        'content_align' => 'center',
                        'valign'        => 'center',
                        'min_height'    => 480,
                    ];
                    foreach ($defaults as $k => $v) {
                        if (!isset($el['settings'][$k])) $el['settings'][$k] = $v;
                    }
                    $converted++;
                    $pageChanged = true;
                }
            }
            unset($el);

            if ($pageChanged) {
                $pages++;
                $newJson = wp_json_encode($tree);
                if ($newJson === false || $newJson === null) {
                    // phpcs:disable WordPress.PHP.DevelopmentFunctions -- server-side error capture / one-time migration logging, not debug output.
                    error_log(sprintf('[Instinctor migration 0021] page %d: json_encode failed, skipping', $pageId));
                    // phpcs:enable WordPress.PHP.DevelopmentFunctions
                    continue;
                }
                $now = current_time('mysql');
                \Instinctor\Core\DB::query(
                    \Instinctor\Core\DB::prepare(
                        "UPDATE {$table} SET elements = %s, updated_at = %s WHERE id = %d",
                        $newJson, $now, $pageId
                    )
                );
            }
        }

        // phpcs:disable WordPress.PHP.DevelopmentFunctions -- server-side error capture / one-time migration logging, not debug output.
        error_log(sprintf(
            '[Instinctor migration 0021] DONE — converted %d storyboard_frame elements across %d pages',
            $converted, $pages
        ));
        // phpcs:enable WordPress.PHP.DevelopmentFunctions
    },

    'down' => [
        // No automatic rollback. The conversion is loss-free in practice
        // (storyboard_frame was structurally a subset of section), but
        // restoring is a manual task if needed.
    ],
];
