<?php

declare(strict_types=1);

namespace App\Framework\View\ValueObjects;

final readonly class FormElement implements HtmlElement
{
    public function __construct(
        public HtmlTag $tag,
        public HtmlAttributes $attributes,
        public string $content = ''
    ) {
        if (! $this->tag->isFormElement()) {
            throw new \InvalidArgumentException("Tag {$this->tag} is not a form element");
        }
    }

    public static function form(string $action = '', string $method = 'post', ?string $htmlId = null): self
    {
        $attributes = HtmlAttributes::empty()
            ->withAction($action)
            ->withMethod($method);

        if ($htmlId) {
            $attributes = $attributes->withId($htmlId);
        }

        return new self(HtmlTag::form(), $attributes);
    }

    public static function input(string $type, string $name, string $value = ''): self
    {
        $attributes = HtmlAttributes::empty()
            ->withType($type)
            ->withName($name);

        if ($value !== '') {
            $attributes = $attributes->withValue($value);
        }

        return new self(HtmlTag::input(), $attributes);
    }

    public static function hiddenInput(string $name, string $value): self
    {
        return self::input('hidden', $name, $value);
    }

    public static function textInput(string $name, string $value = ''): self
    {
        return self::input('text', $name, $value);
    }

    public static function emailInput(string $name, string $value = ''): self
    {
        return self::input('email', $name, $value);
    }

    public static function passwordInput(string $name): self
    {
        return self::input('password', $name);
    }

    public static function fileInput(string $name): self
    {
        return self::input('file', $name);
    }

    public static function submitButton(string $text = 'Submit'): self
    {
        $attributes = HtmlAttributes::empty()->withType('submit');

        return new self(HtmlTag::button(), $attributes, $text);
    }

    public static function button(string $text, string $type = 'button'): self
    {
        $attributes = HtmlAttributes::empty()->withType($type);

        return new self(HtmlTag::button(), $attributes, $text);
    }

    public static function label(string $text, string $for = ''): self
    {
        $attributes = $for ? HtmlAttributes::empty()->with('for', $for) : HtmlAttributes::empty();

        return new self(HtmlTag::label(), $attributes, $text);
    }

    public static function textarea(string $name, string $content = ''): self
    {
        $attributes = HtmlAttributes::empty()->withName($name);

        return new self(HtmlTag::textarea(), $attributes, $content);
    }

    public function withAttribute(string $name, ?string $value = null): self
    {
        return new self($this->tag, $this->attributes->with($name, $value), $this->content);
    }

    public function withRequired(): self
    {
        return new self($this->tag, $this->attributes->withRequired(), $this->content);
    }

    public function withDisabled(): self
    {
        return new self($this->tag, $this->attributes->withDisabled(), $this->content);
    }

    public function withClass(string $class): self
    {
        return new self($this->tag, $this->attributes->withClass($class), $this->content);
    }

    public function withId(string $id): self
    {
        return new self($this->tag, $this->attributes->withId($id), $this->content);
    }

    public function __toString(): string
    {
        $tagName = (string) $this->tag;
        $attributesString = (string) $this->attributes;
        $attributesPart = $attributesString ? " {$attributesString}" : '';

        if ($this->tag->isSelfClosing()) {
            return "<{$tagName}{$attributesPart}>";
        }

        return "<{$tagName}{$attributesPart}>{$this->content}</{$tagName}>";
    }
}
