<?php

/**
 * Migration 0022 — Remove storyboard element type entirely
 *
 * Storyboard was an experimental block (introduced 2.1.439, killed 2.1.453)
 * that turned out to overlap entirely with Scene mode. The right
 * architecture is to make Scene itself a placeable container so
 * multiple cinematic moments per page work natively — without
 * maintaining a parallel scroll-pinned widget. See Scene-as-block
 * roadmap. No real user content ever lived in a Storyboard, so the
 * cleanup is a destructive sweep rather than a preserving conversion.
 *
 * This migration:
 *   • Deletes every element with type='storyboard' across all pages
 *   • Deletes any descendants of those elements (nested sections that
 *     served as auto-seeded frames)
 *   • Deletes any leftover `storyboard_frame` elements (legacy type
 *     converted to `section` by migration 0021; defensive against
 *     pages that somehow re-acquired the type since then)
 *
 * Idempotent — re-running has no effect after the first pass.
 *
 * @since 2.1.453
 */

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

return [
    'description' => 'Remove all storyboard + storyboard_frame elements (block type retired in favour of Scene-as-block)',

    '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 0022] No pages to scan.');
            // phpcs:enable WordPress.PHP.DevelopmentFunctions
            return;
        }

        $pagesTouched = 0;
        $elementsDeleted = 0;

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

            $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) || empty($tree)) continue;

            // Find storyboard / storyboard_frame ids first.
            $kill = [];
            foreach ($tree as $el) {
                if (!is_array($el)) continue;
                $t = $el['type'] ?? '';
                if ($t === 'storyboard' || $t === 'storyboard_frame') {
                    $kill[$el['id']] = true;
                }
            }
            if (empty($kill)) continue;

            // Cascade: any element whose parent_id transitively rolls up
            // to a doomed storyboard is also doomed.
            $changed = true;
            while ($changed) {
                $changed = false;
                foreach ($tree as $el) {
                    if (!is_array($el) || !isset($el['id'])) continue;
                    if (isset($kill[$el['id']])) continue;
                    $pid = $el['parent_id'] ?? null;
                    if ($pid !== null && isset($kill[$pid])) {
                        $kill[$el['id']] = true;
                        $changed = true;
                    }
                }
            }

            $surviving = [];
            foreach ($tree as $el) {
                if (!is_array($el) || !isset($el['id'])) continue;
                if (isset($kill[$el['id']])) continue;
                $surviving[] = $el;
            }

            $dropped = count($tree) - count($surviving);
            if ($dropped > 0) {
                $elementsDeleted += $dropped;
                $pagesTouched++;
                // phpcs:disable WordPress.PHP.DevelopmentFunctions -- server-side error capture / one-time migration logging, not debug output.
                error_log(sprintf(
                    '[Instinctor migration 0022] page %d: %d -> %d elements (dropped %d storyboard + descendants)',
                    $pageId, count($tree), count($surviving), $dropped
                ));
                // phpcs:enable WordPress.PHP.DevelopmentFunctions

                $newJson = wp_json_encode($surviving);
                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 0022] 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 0022] DONE — touched %d page(s), dropped %d element(s) total',
            $pagesTouched, $elementsDeleted
        ));
        // phpcs:enable WordPress.PHP.DevelopmentFunctions
    },

    'down' => [],
];
