<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class IDVE_Renderer {

    private $blocks;

    public function __construct( IDVE_Blocks $blocks ) {
        $this->blocks = $blocks;
    }

    public function render( $tree ) {
        if ( ! isset( $tree['sections'] ) || ! is_array( $tree['sections'] ) ) {
            return '';
        }
        $html = '';
        foreach ( $tree['sections'] as $section ) {
            $html .= $this->render_section( $section );
        }
        return $html;
    }

    private function render_section( $section ) {
        $settings = isset( $section['settings'] ) ? $section['settings'] : array();
        $id       = isset( $section['id'] ) ? $section['id'] : '';
        $stretch  = isset( $settings['stretch'] ) ? $settings['stretch'] : 'default';
        $classes  = array( 'idve-section' );

        if ( ! empty( $settings['cssClass'] ) ) {
            $classes[] = sanitize_html_class( $settings['cssClass'] );
        }

        if ( 'full' === $stretch ) {
            $classes[] = 'idve-section-stretch-full';
        } elseif ( 'full-bg' === $stretch ) {
            $classes[] = 'idve-section-stretch-bg';
        }

        $style_parts = $this->settings_to_style( $settings );

        if ( 'default' !== $stretch ) {
            $style_parts[] = 'width:100vw';
            $style_parts[] = 'margin-left:calc(-50vw + 50%)';
            $style_parts[] = 'margin-right:0';
        }

        $style_attr = $this->build_style_attr( $style_parts );

        $attrs = 'class="' . esc_attr( implode( ' ', $classes ) ) . '" data-idve-id="' . esc_attr( $id ) . '"';
        if ( ! empty( $settings['cssId'] ) ) {
            $attrs .= ' id="' . esc_attr( $settings['cssId'] ) . '"';
        }
        $attrs .= $style_attr;
        $html = '<div ' . $attrs . '>';

        $use_inner = false;
        if ( 'full' === $stretch ) {
            // Full width: no inner wrapper
        } elseif ( 'full-bg' === $stretch ) {
            $max_w = ! empty( $settings['contentMaxWidth'] ) ? $settings['contentMaxWidth'] : '1200px';
            $html .= '<div class="idve-section-inner" style="max-width:' . esc_attr( $max_w ) . ';margin:0 auto">';
            $use_inner = true;
        } else {
            $max_width = ! empty( $settings['maxWidth'] ) ? $settings['maxWidth'] : '';
            if ( $max_width ) {
                $html .= '<div class="idve-section-inner" style="max-width:' . esc_attr( $max_width ) . ';margin:0 auto">';
                $use_inner = true;
            }
        }

        if ( isset( $section['rows'] ) && is_array( $section['rows'] ) ) {
            foreach ( $section['rows'] as $row ) {
                $html .= $this->render_row( $row );
            }
        }

        if ( $use_inner ) {
            $html .= '</div>';
        }

        $html .= '</div>';
        return $html;
    }

    private function render_row( $row ) {
        $id       = isset( $row['id'] ) ? $row['id'] : '';
        $settings = isset( $row['settings'] ) ? $row['settings'] : array();
        $classes  = array( 'idve-row' );

        if ( ! empty( $settings['equalHeight'] ) ) {
            $classes[] = 'idve-row-equal-height';
        }

        if ( ! empty( $settings['cssClass'] ) ) {
            $classes[] = sanitize_html_class( $settings['cssClass'] );
        }

        $style_parts = $this->settings_to_style( $settings );

        $equal_height = ! empty( $settings['equalHeight'] );

        if ( $equal_height ) {
            $style_parts[] = 'display:flex';
            $style_parts[] = 'flex-wrap:wrap';
            $style_parts[] = 'align-items:stretch';
        }

        if ( ! empty( $settings['gap'] ) ) {
            $style_parts[] = 'gap:' . esc_attr( $settings['gap'] );
        }

        $style_attr = $this->build_style_attr( $style_parts );

        $attrs = 'class="' . esc_attr( implode( ' ', $classes ) ) . '" data-idve-id="' . esc_attr( $id ) . '"';
        if ( ! empty( $settings['cssId'] ) ) {
            $attrs .= ' id="' . esc_attr( $settings['cssId'] ) . '"';
        }
        $attrs .= $style_attr;
        $html = '<div ' . $attrs . '>';

        $gap       = ! empty( $settings['gap'] ) ? $settings['gap'] : '';
        $col_count = isset( $row['columns'] ) ? count( $row['columns'] ) : 0;

        if ( isset( $row['columns'] ) && is_array( $row['columns'] ) ) {
            foreach ( $row['columns'] as $col ) {
                $html .= $this->render_column( $col, $equal_height, $gap, $col_count );
            }
        }

        $html .= '</div>';
        return $html;
    }

    private function render_column( $col, $equal_height = false, $gap = '', $col_count = 0 ) {
        $settings = isset( $col['settings'] ) ? $col['settings'] : array();
        $id       = isset( $col['id'] ) ? $col['id'] : '';
        $width    = isset( $col['width'] ) ? $col['width'] : '1/1';
        $classes  = array( 'idve-col' );

        $parts = explode( '/', $width );
        if ( count( $parts ) === 2 ) {
            $classes[] = 'idve-col-' . intval( $parts[0] ) . '-' . intval( $parts[1] );
        }

        if ( ! empty( $settings['cssClass'] ) ) {
            $classes[] = sanitize_html_class( $settings['cssClass'] );
        }

        $style_parts = $this->settings_to_style( $settings );

        // When gap is set, adjust flex-basis to account for gap space
        if ( $gap && $col_count > 1 ) {
            $width_map = array(
                '1/1' => 100, '1/2' => 50, '1/3' => 33.333, '2/3' => 66.667,
                '1/4' => 25, '3/4' => 75, '1/5' => 20, '2/5' => 40, '3/5' => 60, '4/5' => 80,
            );
            $pct       = isset( $width_map[ $width ] ) ? $width_map[ $width ] : 100;
            $gaps      = $col_count - 1;
            $adjusted  = 'calc(' . $pct . '% - ' . $gaps . ' * ' . esc_attr( $gap ) . ' / ' . $col_count . ')';
            $style_parts[] = 'flex-basis:' . $adjusted;
            $style_parts[] = 'max-width:' . $adjusted;
        }

        if ( $equal_height ) {
            $style_parts[] = 'display:flex';
            $style_parts[] = 'flex-direction:column';
            // Use justify-content to align content INSIDE the stretched column
            if ( ! empty( $settings['verticalAlign'] ) && 'top' !== $settings['verticalAlign'] ) {
                $map = array( 'center' => 'center', 'bottom' => 'flex-end' );
                if ( isset( $map[ $settings['verticalAlign'] ] ) ) {
                    $style_parts[] = 'justify-content:' . $map[ $settings['verticalAlign'] ];
                }
            }
        } else {
            // Use align-self to position the column within the row
            if ( ! empty( $settings['verticalAlign'] ) && 'top' !== $settings['verticalAlign'] ) {
                $map = array( 'center' => 'center', 'bottom' => 'flex-end' );
                if ( isset( $map[ $settings['verticalAlign'] ] ) ) {
                    $style_parts[] = 'align-self:' . $map[ $settings['verticalAlign'] ];
                }
            }
        }

        $style_attr = $this->build_style_attr( $style_parts );

        $attrs = 'class="' . esc_attr( implode( ' ', $classes ) ) . '" data-idve-id="' . esc_attr( $id ) . '"';
        if ( ! empty( $settings['cssId'] ) ) {
            $attrs .= ' id="' . esc_attr( $settings['cssId'] ) . '"';
        }
        $attrs .= $style_attr;
        $html = '<div ' . $attrs . '>';

        if ( isset( $col['blocks'] ) && is_array( $col['blocks'] ) ) {
            foreach ( $col['blocks'] as $block ) {
                $html .= $this->render_block( $block );
            }
        }

        $html .= '</div>';
        return $html;
    }

    public function render_block( $block ) {
        $type     = isset( $block['type'] ) ? $block['type'] : '';
        $data     = isset( $block['data'] ) ? $block['data'] : array();
        $settings = isset( $block['settings'] ) ? $block['settings'] : array();
        $id       = isset( $block['id'] ) ? $block['id'] : '';
        $classes  = array( 'idve-block', 'idve-block-' . sanitize_html_class( $type ) );

        // Button, image, and icon blocks apply cssClass to their inner element, not the wrapper div.
        if ( ! empty( $settings['cssClass'] ) && 'button' !== $type && 'image' !== $type && 'icon' !== $type ) {
            $classes[] = sanitize_html_class( $settings['cssClass'] );
        }

        $visible = isset( $settings['visible'] ) ? $settings['visible'] : true;

        // Build inline styles from settings (buttons, images, and icons handle their own — wrapper is alignment only)
        $style_parts = ( 'button' === $type || 'image' === $type || 'icon' === $type ) ? array() : $this->settings_to_style( $settings );

        if ( ! $visible ) {
            $style_parts[] = 'display:none';
        }

        // Block-type specific wrapper styles
        switch ( $type ) {
            case 'text':
                if ( ! empty( $data['alignment'] ) ) {
                    $style_parts[] = 'text-align:' . sanitize_key( $data['alignment'] );
                }
                if ( ! empty( $data['textColor'] ) ) {
                    $c = $this->sanitize_color( $data['textColor'] );
                    if ( $c ) {
                        $style_parts[] = 'color:' . $c;
                    }
                }
                if ( ! empty( $data['fontSize'] ) ) {
                    $style_parts[] = 'font-size:' . esc_attr( $data['fontSize'] );
                }
                break;

            case 'heading':
            case 'image':
            case 'button':
                if ( ! empty( $data['alignment'] ) ) {
                    $style_parts[] = 'text-align:' . sanitize_key( $data['alignment'] );
                }
                break;

            case 'spacer':
                $height = isset( $data['height'] ) ? absint( $data['height'] ) : 40;
                $style_parts[] = 'height:' . $height . 'px';
                break;

            case 'icon':
                if ( ! empty( $data['alignment'] ) ) {
                    $style_parts[] = 'text-align:' . sanitize_key( $data['alignment'] );
                }
                break;

            case 'group':
                if ( ! empty( $data['minHeight'] ) ) {
                    $style_parts[] = 'min-height:' . esc_attr( $data['minHeight'] );
                }
                if ( ! empty( $settings['verticalAlign'] ) && 'top' !== $settings['verticalAlign'] ) {
                    $style_parts[] = 'display:flex';
                    $style_parts[] = 'flex-direction:column';
                    $map = array( 'center' => 'center', 'bottom' => 'flex-end' );
                    if ( isset( $map[ $settings['verticalAlign'] ] ) ) {
                        $style_parts[] = 'justify-content:' . $map[ $settings['verticalAlign'] ];
                    }
                }
                $classes[] = 'idve-group';
                break;
        }

        $style_attr = $this->build_style_attr( $style_parts );

        $attrs = 'class="' . esc_attr( implode( ' ', $classes ) ) . '" data-idve-id="' . esc_attr( $id ) . '"';
        if ( ! empty( $settings['cssId'] ) ) {
            $attrs .= ' id="' . esc_attr( $settings['cssId'] ) . '"';
        }
        $attrs .= $style_attr;
        if ( ! $visible ) {
            $attrs .= ' data-idve-hidden="1"';
        }

        if ( 'group' === $type ) {
            $inner = '';
            if ( ! empty( $block['blocks'] ) ) {
                foreach ( $block['blocks'] as $child ) {
                    $inner .= $this->render_block( $child );
                }
            }
        } else {
            $inner = $this->blocks->render( $type, $data, $settings );
        }

        return '<div ' . $attrs . '>' . $inner . '</div>';
    }

    // ── Style Helpers ──

    private function sanitize_color( $color ) {
        if ( empty( $color ) || 'transparent' === $color ) {
            return '';
        }
        if ( preg_match( '/^#[0-9a-fA-F]{3,8}$/', $color ) ) {
            return $color;
        }
        if ( preg_match( '/^rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*(,\s*[\d.]+)?\s*\)$/', $color ) ) {
            return $color;
        }
        return '';
    }

    private function format_spacing( $spacing ) {
        if ( empty( $spacing ) || ! is_array( $spacing ) ) {
            return '';
        }
        $t = isset( $spacing['top'] ) ? intval( $spacing['top'] ) : 0;
        $r = isset( $spacing['right'] ) ? intval( $spacing['right'] ) : 0;
        $b = isset( $spacing['bottom'] ) ? intval( $spacing['bottom'] ) : 0;
        $l = isset( $spacing['left'] ) ? intval( $spacing['left'] ) : 0;
        if ( 0 === $t && 0 === $r && 0 === $b && 0 === $l ) {
            return '';
        }
        return $t . 'px ' . $r . 'px ' . $b . 'px ' . $l . 'px';
    }

    private function format_border( $border ) {
        if ( empty( $border ) || ! is_array( $border ) ) {
            return array();
        }
        $parts = array();
        $color = ! empty( $border['color'] ) ? $this->sanitize_color( $border['color'] ) : '#000000';
        $style = ! empty( $border['style'] ) ? sanitize_key( $border['style'] ) : 'solid';

        if ( ! empty( $border['width'] ) && is_array( $border['width'] ) ) {
            foreach ( array( 'top', 'right', 'bottom', 'left' ) as $side ) {
                $w = isset( $border['width'][ $side ] ) ? absint( $border['width'][ $side ] ) : 0;
                if ( $w > 0 && $color ) {
                    $parts[] = 'border-' . $side . ':' . $w . 'px ' . $style . ' ' . $color;
                }
            }
        }

        if ( ! empty( $border['radius'] ) && is_array( $border['radius'] ) ) {
            $tl = isset( $border['radius']['topLeft'] ) ? absint( $border['radius']['topLeft'] ) : 0;
            $tr = isset( $border['radius']['topRight'] ) ? absint( $border['radius']['topRight'] ) : 0;
            $br = isset( $border['radius']['bottomRight'] ) ? absint( $border['radius']['bottomRight'] ) : 0;
            $bl = isset( $border['radius']['bottomLeft'] ) ? absint( $border['radius']['bottomLeft'] ) : 0;
            if ( $tl || $tr || $br || $bl ) {
                $parts[] = 'border-radius:' . $tl . 'px ' . $tr . 'px ' . $br . 'px ' . $bl . 'px';
            }
        }

        return $parts;
    }

    private function settings_to_style( $settings ) {
        $parts = array();
        if ( ! empty( $settings['backgroundColor'] ) ) {
            $c = $this->sanitize_color( $settings['backgroundColor'] );
            if ( $c ) {
                $parts[] = 'background-color:' . $c;
            }
        }
        if ( ! empty( $settings['backgroundImage'] ) ) {
            $parts[] = 'background-image:url(' . esc_url( $settings['backgroundImage'] ) . ')';
            $size = ! empty( $settings['backgroundSize'] ) ? $settings['backgroundSize'] : 'cover';
            $parts[] = 'background-size:' . esc_attr( $size );
            $pos = ! empty( $settings['backgroundPosition'] ) ? $settings['backgroundPosition'] : 'center';
            $parts[] = 'background-position:' . esc_attr( $pos );
            $rep = ! empty( $settings['backgroundRepeat'] ) ? $settings['backgroundRepeat'] : 'no-repeat';
            $parts[] = 'background-repeat:' . esc_attr( $rep );
        }
        $p = $this->format_spacing( isset( $settings['padding'] ) ? $settings['padding'] : null );
        if ( $p ) {
            $parts[] = 'padding:' . $p;
        }
        $m = $this->format_spacing( isset( $settings['margin'] ) ? $settings['margin'] : null );
        if ( $m ) {
            $parts[] = 'margin:' . $m;
        }
        $border_parts = $this->format_border( isset( $settings['border'] ) ? $settings['border'] : null );
        $parts = array_merge( $parts, $border_parts );

        return $parts;
    }

    private function build_style_attr( $parts ) {
        $filtered = array_filter( $parts );
        if ( empty( $filtered ) ) {
            return '';
        }
        return ' style="' . esc_attr( implode( ';', $filtered ) ) . '"';
    }
}
