<?php
// components/CampaignFlow/FlowViz.php
namespace Components\CampaignFlow;

use Components\Base;

class FlowViz extends Base
{
    /**
     * Render a campaign flow visualization from a sequence of items.
     * $items: array of elements like
     *   [
     *     // Preferred explicit keys for StepCard:
     *     // - steptype: primary line (step type)
     *     // - content: secondary line (step content)
     *     // Legacy keys title/subtitle are still accepted by StepCard.
     *     ['type'=>'step','id'=>'trigger','steptype'=>'Trigger','content'=>'Last Purchase','icon'=>'⚡','color'=>'blue', 'markers' => [['color'=>'blue','label'=>'Filter applied']]],
     *     ['type'=>'wait','label'=>'Wait 3 days','icon'=>'⏱', 'index'=>0],
     *     ['type'=>'step','id'=>'step1','steptype'=>'Step 1','content'=>'Reminder Email','icon'=>'📧','color'=>'indigo', 'markers' => [['color'=>'red','label'=>'Coupon']]],
     *     ['type'=>'add','icon'=>Base::SVG_ADD],
     *     ...
     *   ]
     * $opts:
     *  - orientation: 'horizontal'|'vertical' (default: 'horizontal')
     *  - size: 'xs'|'sm'|'md'|'lg' (default: 'md')
     *  - editable: bool (default: false)
     *  - class: extra classes for wrapper
     */
    public static function render(array $items, array $opts = []): string
    {
        $orientation = $opts['orientation'] ?? 'horizontal';
        $size = $opts['size'] ?? 'md';
        $id = $opts['id'] ?? 'flowViz';
        $editable = (bool)($opts['editable'] ?? false);
        $extraClass = trim((string)($opts['class'] ?? ''));

        $wrapBase = '';
        $dirCls = $orientation === 'vertical'
            ? 'flex flex-col  w-full space-y-2'
            : 'flex items-center shrink max-w-full';

        $wrapperCls = trim($wrapBase . ' ' . $dirCls . ' ' . $extraClass);
        $wrapperClsEsc = self::h($wrapperCls);

        ob_start();
        echo <<<HTML
<div class="{$wrapperClsEsc}" id="{$id}">
HTML;

        $count = count($items);
        $hasExplicitAdd = false;
        for ($i = 0; $i < $count; $i++) {
            $it = $items[$i];
            $type = $it['type'] ?? 'step';

            // If this item is a 'branch' and previous item wasn't a wait/date_range/add, insert a connector first
            if ($i > 0 && $type === 'branch') {
                $prevType = $items[$i-1]['type'] ?? 'step';
                if ($prevType !== 'wait' && $prevType !== 'date_range' && $prevType !== 'add') {
                    $prevDisabled = (bool)($items[$i-1]['disabled'] ?? false);
                    $currDisabled = (bool)($it['disabled'] ?? false);
                    echo Connector::render(null, [
                        'orientation' => $orientation,
                        'size' => $size,
                        'editable' => $editable,
                        'disabled' => ($prevDisabled || $currDisabled),
                    ]);
                }
            }

            if ($type === 'step') {
                echo StepCard::render($it, ['size' => $size, 'editable' => $editable]);
            } elseif ($type === 'wait' || $type === 'condition' || $type === 'date_range') {
                // Render a connector hosting the wait/condition/date_range badge
                // Between adjacent badges, suppress any elements on the left side of the
                // current badge (arrow AND line) so badges move closer and only the
                // previous badge's right arrow remains between them.
                $prevType = $i > 0 ? ($items[$i-1]['type'] ?? null) : null;
                $prevIsBadge = in_array($prevType, ['wait','condition','date_range'], true);
                $nextType = $i < $count - 1 ? ($items[$i+1]['type'] ?? null) : null;
                $nextIsBadge = in_array($nextType, ['wait','condition','date_range'], true);
                echo Connector::render($it, [
                    'orientation' => $orientation,
                    'size' => $size,
                    'editable' => $editable,
                    'left_arrow' => !$prevIsBadge,
                    'left_line' => !$prevIsBadge,
                    // If the next item is also a badge, hide the right arrow + line of this badge
                    // so the badges move closer with no line segment between them.
                    'right_arrow' => true, // !$nextIsBadge,
                    'right_line' => true, // !$nextIsBadge,
                ]);
            } elseif ($type === 'branch') {
                // Special case: adjacent branch() + merge() can be rendered as a single combined block
                // to avoid duplicating lane steps while still drawing a correct convergence.
                $next = $i < $count - 1 ? ($items[$i + 1] ?? null) : null;
                $nextIsMergeFromBranch = is_array($next)
                    && (($next['type'] ?? null) === 'merge')
                    && (bool)($next['from_branch'] ?? false);

                if ($nextIsMergeFromBranch) {
                    echo BranchMergeViz::render($it, $next, [
                        'size' => $size,
                        'editable' => $editable,
                        'addTail' => $opts['addTail'] ?? null,
                    ]);

                    // After a branch+merge combined block, the main flow continues as a single trunk.
                    // Mirror the merge-to-step connector behavior.
                    $after = $i < $count - 2 ? ($items[$i + 2] ?? null) : null;
                    if (is_array($after) && (($after['type'] ?? null) === 'step')) {
                        $currDisabled = (bool)($it['disabled'] ?? false) || (bool)($next['disabled'] ?? false);
                        $nextDisabled = (bool)($after['disabled'] ?? false);
                        echo Connector::render(null, [
                            'orientation' => $orientation,
                            'size' => $size,
                            'editable' => $editable,
                            'disabled' => ($currDisabled || $nextDisabled),
                        ]);
                    }

                    // Skip the merge item, it is already rendered together with the branch.
                    $i++;
                    continue;
                }

                echo BranchViz::render($it, ['size' => $size, 'editable' => $editable, 'addTail' => $opts['addTail'] ?? null]);
            } elseif ($type === 'merge') {
                echo MergeViz::render($it, ['size' => $size, 'editable' => $editable, 'addTail' => $opts['addTail'] ?? null]);
            } elseif ($type === 'add') {
                // Explicit AddTail item support
                $hasExplicitAdd = true;
                // Render regardless of overall editable to ensure visibility across sizes
                echo AddTail::render([
                    'orientation' => $orientation,
                    'size' => $size,
                    'editable' => true,
                    'href' => $it['href'] ?? null,
                    'attrs' => $it['attrs'] ?? [],
                    'icon' => $it['icon'] ?? null,
                ]);
            } else {
                // Unknown type: skip
                continue;
            }

            // If current is step and next is step (not branch) and there is no explicit wait in between, insert connector
            // Branches are handled explicitly at the beginning of their iteration to avoid duplicate connectors
            if ($type === 'step' && $i < $count - 1) {
                $next = $items[$i+1];
                $nextType = $next['type'] ?? 'step';
                if ($nextType === 'step') {
                    $currDisabled = (bool)($it['disabled'] ?? false);
                    $nextDisabled = (bool)($next['disabled'] ?? false);
                    echo Connector::render(null, [
                        'orientation' => $orientation,
                        'size' => $size,
                        'editable' => $editable,
                        'disabled' => ($currDisabled || $nextDisabled),
                    ]);
                }
            }

            // After a merge block, the main flow continues as a single trunk.
            // If the next item is a step, insert a connector so the layout matches step-to-step flows.
            if ($type === 'merge' && $i < $count - 1) {
                $next = $items[$i+1];
                $nextType = $next['type'] ?? 'step';
                if ($nextType === 'step') {
                    $currDisabled = (bool)($it['disabled'] ?? false);
                    $nextDisabled = (bool)($next['disabled'] ?? false);
                    echo Connector::render(null, [
                        'orientation' => $orientation,
                        'size' => $size,
                        'editable' => $editable,
                        'disabled' => ($currDisabled || $nextDisabled),
                    ]);
                }
            }
        }

        // Add an end-of-flow AddTail when editable, controlled by data param "addTail"
        // The "addTail" flag can be provided either:
        // - in $opts['addTail'] (boolean), or
        // - inside any item in $items as ['addTail' => true|false]
        // Backwards compatible: if not provided, defaults to previous behavior (show when editable).
        $showTail = $opts['addTail'] ?? null;
        foreach ($items as $it) {
            if (array_key_exists('addTail', $it)) {
                $showTail = (bool)$it['addTail'];
                break;
            }
        }
        $showTail = $showTail === null ? $editable : (bool)$showTail;

        if ($showTail && !$hasExplicitAdd) {
//            echo Connector::render(null, ['orientation' => $orientation, 'size' => $size, 'editable' => $editable]);
            echo AddTail::render(['orientation' => $orientation, 'size' => $size, 'editable' => $editable]);
        }

        echo <<<HTML
</div>
HTML;
        return ob_get_clean();
    }
}
