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

use Components\Base;

/**
 * Render an adjacent branch + merge as a single combined block.
 *
 * Purpose:
 * - keep a visually correct convergence
 * - avoid duplicating the lane steps (branch lane content is rendered once)
 *
 * The merge part may contain optional lane continuations (additional items appended
 * inside each lane before the merge connector).
 */
class BranchMergeViz extends Base
{
    public static function render(array $branch, array $merge, array $opts = []): string
    {
        $size = $opts['size'] ?? 'md'; // xs|sm|md|lg
        $editable = (bool)($opts['editable'] ?? false);

        $gap = (string)($merge['gap'] ?? ($branch['gap'] ?? 'md'));
        if ($gap === 'sm') {
            $gapY = 'gap-y-4';
            $gapFactorY = 4;
        } elseif ($gap === 'lg') {
            $gapY = 'gap-y-12';
            $gapFactorY = 12;
        } else {
            $gapY = 'gap-y-8';
            $gapFactorY = 8;
        }

        // Lane paddings so elbows have some vertical room to look rounded
        if ($size === 'xs') {
            $lanePadY = 'py-1';
        } elseif ($size === 'sm') {
            $lanePadY = 'py-2';
        } elseif ($size === 'lg') {
            $lanePadY = 'py-4';
        } else {
            $lanePadY = 'py-3';
        }

        // Left column width hosting the branch trunk + elbows
        if ($size === 'xs') {
            $leftW = 20;
        } elseif ($size === 'sm') {
            $leftW = 28;
        } elseif ($size === 'lg') {
            $leftW = 36;
        } else {
            $leftW = 32;
        }

        // Right column width hosting the merge trunk + elbows
        if ($size === 'xs') {
            $rightW = 20;
        } elseif ($size === 'sm') {
            $rightW = 28;
        } elseif ($size === 'lg') {
            $rightW = 36;
        } else {
            $rightW = 32;
        }

        $leftCenter = (int)floor($leftW / 2);
        $rightCenter = (int)floor($rightW / 2);

        // Branch elbow box width per size
        if ($size === 'xs') {
            $leftElbowW = 16;   // w-4
            $radiusTL = 'rounded-tl-md';
            $radiusBL = 'rounded-bl-md';
        } elseif ($size === 'sm') {
            $leftElbowW = 20;   // w-5
            $radiusTL = 'rounded-tl-lg';
            $radiusBL = 'rounded-bl-lg';
        } elseif ($size === 'lg') {
            $leftElbowW = 28;   // ~w-7
            $radiusTL = 'rounded-tl-2xl';
            $radiusBL = 'rounded-bl-2xl';
        } else {
            // md
            $leftElbowW = 24;   // w-6
            $radiusTL = 'rounded-tl-xl';
            $radiusBL = 'rounded-bl-xl';
        }

        // Merge elbow box width per size
        if ($size === 'xs') {
            $rightElbowW = 16;   // w-4
            $radiusTR = 'rounded-tr-md';
            $radiusBR = 'rounded-br-md';
        } elseif ($size === 'sm') {
            $rightElbowW = 20;   // w-5
            $radiusTR = 'rounded-tr-lg';
            $radiusBR = 'rounded-br-lg';
        } elseif ($size === 'lg') {
            $rightElbowW = 28;   // ~w-7
            $radiusTR = 'rounded-tr-2xl';
            $radiusBR = 'rounded-br-2xl';
        } else {
            // md
            $rightElbowW = 24;   // w-6
            $radiusTR = 'rounded-tr-xl';
            $radiusBR = 'rounded-br-xl';
        }

        // Compose branch lanes list: prefer 'lanes' (N lanes), fallback to 'top'/'bottom'
        $branchLanes = [];
        if (isset($branch['lanes']) && is_array($branch['lanes'])) {
            foreach ($branch['lanes'] as $li) {
                $branchLanes[] = is_array($li) ? $li : [];
            }
        } else {
            $topItems = is_array($branch['top'] ?? null) ? $branch['top'] : [];
            $bottomItems = is_array($branch['bottom'] ?? null) ? $branch['bottom'] : [];
            if ($topItems !== [] || $bottomItems !== []) {
                $branchLanes = [$topItems, $bottomItems];
            }
        }
        if (!$branchLanes) {
            return '';
        }

        // Optional lane continuations (built by FlowBuilder::merge() when called after branch())
        $cont = [];
        if (isset($merge['continuations']) && is_array($merge['continuations'])) {
            foreach ($merge['continuations'] as $li) {
                $cont[] = is_array($li) ? $li : [];
            }
        }

        // Prepare per-lane HTML using FlowViz recursion
        $laneHtmls = [];
        foreach ($branchLanes as $i => $li) {
            $suffix = $cont[$i] ?? [];
            $laneItems = array_merge(is_array($li) ? $li : [], is_array($suffix) ? $suffix : []);
            $laneHtmls[] = FlowViz::render($laneItems, [
                'orientation' => 'horizontal',
                'size' => $size,
                'editable' => $editable,
                'addTail' => $opts['addTail'] ?? null,
            ]);
        }

        // Build HTML using output buffering (ob_start) to comply with inline HTML guidelines
        $gridCls = 'grid ' . $gapY . ' ' . $lanePadY;
        // Use max-content for the lane column to avoid stretching (prevents merge misalignment)
        $gridStyle = 'grid-template-columns: ' . $leftW . 'px max-content ' . $rightW . 'px';

        $addedLeftWidth = 100; // additional length to left to compensate for steps with different widths
        ob_start();
        ?>
        <div class="relative z-10" style="max-width: 100%">
            <!-- Intro horizontal line from left edge into the branch trunk center -->
            <div class="pointer-events-none absolute left-0 top-1/2 -translate-y-1/2 h-px bg-flow"
                 style="width: <?= (int)$leftCenter ?>px">
                <div class="absolute size-2 rounded-full bg-flow -right-1 -top-1"></div>
            </div>

            <!-- Outro horizontal line from merge trunk center to the right edge (connects to the main flow) -->
            <div class="pointer-events-none absolute right-0 top-1/2 -translate-y-1/2 h-px bg-flow"
                 style="width: <?= (int)($rightW - $rightCenter) ?>px">
                <div class="absolute size-2 rounded-full bg-flow -left-1 -top-1"></div>
            </div>

            <div class="<?= self::h($gridCls) ?>" style="<?= self::h($gridStyle) ?>">
                <?php
                $rowCount = count($laneHtmls);
                foreach ($laneHtmls as $i => $laneHtml):
                    $isFirst = ($i === 0);
                    $isAboveCenter = ($i < ($rowCount - 1) / 2);
                    $isCenter = ($i === ($rowCount - 1) / 2);
                    $isLast = ($i === $rowCount - 1);
                    $isBelowCenter = (!$isLast) ? ($i > ($rowCount - 1) / 2) : false;
                    ?>

                    <!-- Branch trunk + elbows (left) -->
                    <div class="relative">
                        <?php if ($isFirst || $isAboveCenter): ?>
                            <div class="pointer-events-none absolute <?= self::h($radiusTL) ?> border-t border-l border-flow"
                                 style="left: <?= (int)$leftCenter ?>px; top: calc(50%  - 0.5px); width: <?= (int)$leftElbowW ?>px; height: <?= (int)$leftElbowW ?>px"></div>
                        <?php elseif ($isCenter): ?>
                            <div class="pointer-events-none absolute top-1/2 -translate-y-1/2 h-px bg-flow"
                                 style="left: <?= (int)$leftCenter ?>px; width: <?= (int)$leftElbowW ?>px"></div>
                        <?php elseif ($isBelowCenter || $isLast): ?>
                            <div class="pointer-events-none absolute <?= self::h($radiusBL) ?> border-b border-l border-flow"
                                 style="left: <?= (int)$leftCenter ?>px; top: calc(50%  + 0.5px - <?= (int)($leftElbowW) ?>px); width: <?= (int)$leftElbowW ?>px; height: <?= (int)$leftElbowW ?>px"></div>
                        <?php endif; ?>

                        <?php
                        // Vertical trunk segments between lanes (span into the grid gaps)
                        if ($isFirst): ?>
                            <div class="border-l border-flow absolute"
                                 style="left: <?= (int)$leftCenter ?>px; height: calc(50% + (var(--spacing) * 0.5 * <?= (int)$gapFactorY ?>)); top: calc(50% + (var(--spacing) * 0.5 * <?= (int)$gapFactorY ?>));"></div>
                        <?php elseif ($isAboveCenter): ?>
                            <div class="border-l border-flow absolute"
                                 style="left: <?= (int)$leftCenter ?>px; height: calc(100% + (var(--spacing) * 1 * <?= (int)$gapFactorY ?>));"></div>
                        <?php elseif ($isCenter): ?>
                            <div class="border-l border-flow absolute"
                                 style="left: <?= (int)$leftCenter ?>px; height: calc(100% + (var(--spacing) * 1 * <?= (int)$gapFactorY ?>));"></div>
                        <?php elseif ($isBelowCenter): ?>
                            <div class="border-l border-flow absolute"
                                 style="left: <?= (int)$leftCenter ?>px; height: calc(100% + (var(--spacing) * 1 * <?= (int)$gapFactorY ?>));"></div>
                        <?php elseif ($isLast): ?>
                            <div class="border-l border-flow absolute"
                                 style="left: <?= (int)$leftCenter ?>px; height: calc(100% - (var(--spacing) * 0.5 * <?= (int)$gapFactorY ?>)); top: calc(-50%);"></div>
                        <?php endif; ?>
                    </div>

                    <!-- Lane content (middle) -->
                    <div class="relative flex items-center">
                        <?= $laneHtml ?>
                    </div>

                    <!-- Merge trunk + elbows (right) -->
                    <div class="relative -z-1">
                        <?php if ($isFirst || $isAboveCenter): ?>
                            <div class="pointer-events-none absolute <?= self::h($radiusTR) ?> border-t border-r border-flow"
                                 style="left: <?= (int)($rightCenter - $rightElbowW - $addedLeftWidth) ?>px; top: calc(50% - 0.5px); width: <?= (int)$rightElbowW + $addedLeftWidth?>px; height: <?= (int)$rightElbowW ?>px"></div>
                        <?php elseif ($isCenter): ?>
                            <div class="pointer-events-none absolute top-1/2 -translate-y-1/2 h-px bg-flow"
                                 style="left: 0; width: <?= (int)$rightCenter ?>px"></div>
                        <?php elseif ($isBelowCenter || $isLast): ?>
                            <div class="pointer-events-none absolute <?= self::h($radiusBR) ?> border-b border-r border-flow"
                                 style="left: <?= (int)($rightCenter - $rightElbowW - $addedLeftWidth) ?>px; top: calc(50% + 0.5px - <?= (int)$rightElbowW ?>px); width: <?= (int)$rightElbowW  + $addedLeftWidth?>px; height: <?= (int)$rightElbowW ?>px"></div>
                        <?php endif; ?>

                        <?php
                        // Vertical trunk segments between lanes (span into the grid gaps)
                        if ($isFirst): ?>
                            <div class="border-l border-flow absolute"
                                 style="left: <?= (int)$rightCenter - 1 ?>px; height: calc(50% + (var(--spacing) * 0.5 * <?= (int)$gapFactorY ?>)); top: calc(50% + (var(--spacing) * 0.5 * <?= (int)$gapFactorY ?>));"></div>
                        <?php elseif ($isAboveCenter): ?>
                            <div class="border-l border-flow absolute"
                                 style="left: <?= (int)$rightCenter - 1 ?>px; height: calc(100% + (var(--spacing) * 1 * <?= (int)$gapFactorY ?>));"></div>
                        <?php elseif ($isCenter): ?>
                            <div class="border-l border-flow absolute"
                                 style="left: <?= (int)$rightCenter - 1 ?>px; height: calc(100% + (var(--spacing) * 1 * <?= (int)$gapFactorY ?>));"></div>
                        <?php elseif ($isBelowCenter): ?>
                            <div class="border-l border-flow absolute"
                                 style="left: <?= (int)$rightCenter - 1 ?>px; height: calc(100% + (var(--spacing) * 1 * <?= (int)$gapFactorY ?>));"></div>
                        <?php elseif ($isLast): ?>
                            <div class="border-l border-flow absolute"
                                 style="left: <?= (int)$rightCenter - 1 ?>px; height: calc(100% - (var(--spacing) * 0.5 * <?= (int)$gapFactorY ?>)); top: calc(-50%);"></div>
                        <?php endif; ?>
                    </div>

                <?php endforeach; ?>
            </div>
        </div>
        <?php
        return (string)ob_get_clean();
    }
}
