<?php

declare(strict_types=1);

namespace Atk4\Ui\Js;

use Atk4\Core\WarnDynamicPropertyTrait;

class JsFunction implements JsExpressionable
{
    use WarnDynamicPropertyTrait;

    /** @var list<string> */
    public array $args;

    public JsBlock $body;

    /** Add event.preventDefault() to generated method */
    public bool $preventDefault = false;

    /** Add event.stopPropagation() to generated method */
    public bool $stopPropagation = false;

    /** Indent of target code (not one indent level) */
    public string $indent = '';

    /**
     * @param list<string>                                             $args
     * @param JsBlock|list<JsExpressionable|null>|array<string, mixed> $statements
     */
    public function __construct(array $args, $statements)
    {
        $this->args = $args;

        if (!is_array($statements)) {
            $this->body = $statements;
        } else {
            foreach ($statements as $key => $value) {
                if (is_string($key)) {
                    $this->{$key} = $value;
                    unset($statements[$key]);
                } elseif ($value === null) { // TODO this should be not needed
                    unset($statements[$key]);
                }
            }

            $this->body = new JsBlock($statements);
        }
    }

    #[\Override]
    public function jsRender(): string
    {
        $pre = '';
        if ($this->preventDefault) {
            $this->args = ['event'];
            $pre .= $this->indent . '    event.preventDefault();' . "\n";
        }
        if ($this->stopPropagation) {
            $this->args = ['event'];
            $pre .= $this->indent . '    event.stopPropagation();' . "\n";
        }

        $body = $this->body->jsRender();

        $output = $this->indent . 'function (' . implode(', ', $this->args) . ') {';
        if ($body !== '') {
            $output .= "\n" . $pre
                . preg_replace('~^(?!$)~m', $this->indent . '    ', $body) . "\n" // TODO IMPORTANT indentation must ignore multiline strings/comments!
                . $this->indent;
        }
        $output .= '}';

        return $output;
    }
}
