defmodule Raxol.Examples.FormDemo do
  @moduledoc """
  A sample form component that demonstrates parent-child interactions.

  This component includes:
  - Child component management
  - Event bubbling
  - State synchronization
  - Error boundaries
  """

  use Raxol.Core.Runtime.Application
  require Raxol.Core.Runtime.Log
  require Raxol.View.Elements
  alias Raxol.View.Elements, as: UI

  defstruct form_data: %{username: "", password: ""},
            submitted: false,
            id: :form_example

  @doc """
  Initialize the form component with default state (for testing compatibility).
  """
  def new(props \\ %{}) do
    %{
      submitted: false,
      button_clicked: nil,
      fields: Map.get(props, :fields, %{}),
      on_submit: Map.get(props, :on_submit, fn -> :submitted end),
      children: Map.get(props, :children, []),
      errors: Map.get(props, :errors, %{}),
      id: Map.get(props, :id, :form_example),
      form_data: Map.get(props, :form_data, %{username: "", password: ""})
    }
  end

  @impl Raxol.Core.Runtime.Application
  def init(_opts) do
    {:ok, %__MODULE__{}}
  end

  @impl Raxol.Core.Runtime.Application
  def update({:input, field, value}, state) do
    new_form_data = Map.put(state.form_data, field, value)
    {%{state | form_data: new_form_data}, []}
  end

  def update({:submit}, state) do
    # Log submission, don't emit command
    Raxol.Core.Runtime.Log.info("Form submitted: #{inspect(state.form_data)}")
    {%{state | submitted: true}, []}
  end

  def update(_msg, state) do
    # Ignore other messages
    {state, []}
  end

  # Correct arity for Application behaviour
  @impl Raxol.Core.Runtime.Application
  def handle_event(
        {:raxol_event, _source_pid,
         {:component_event, component_id, event_type, payload}}
      ) do
    # Translate component events into update messages
    case {component_id, event_type} do
      # Assuming payload is the new value
      {:username_input, :change} -> [{:input, :username, payload}]
      # Assuming payload is the new value
      {:password_input, :change} -> [{:input, :password, payload}]
      # Assuming any click in the form context is a submit
      {_, :click} -> [:submit]
      # Ignore other component events
      _ -> []
    end
  end

  def handle_event(_event) do
    # State is managed by Dispatcher, just return commands/messages
    # Keep this catch-all for other event types (e.g., keyboard, mouse if needed)
    []
  end

  @impl Raxol.Core.Runtime.Application
  # Keep state for handle_message
  def handle_message(_msg, state), do: {state, []}

  # Correct arity for Application behaviour
  @impl Raxol.Core.Runtime.Application
  def handle_tick(_tick) do
    # State is managed by Dispatcher, just return commands
    []
  end

  @impl Raxol.Core.Runtime.Application
  def subscriptions(_state), do: []

  @impl Raxol.Core.Runtime.Application
  def terminate(_reason, _state), do: :ok

  @doc """
  Render the form UI.
  """
  @impl Raxol.Core.Runtime.Application
  @dialyzer {:nowarn_function, view: 1}
  def view(state) do
    UI.box id: state.id, border: :rounded, padding: 1 do
      UI.column do
        [
          UI.label("Username:"),
          UI.text_input(id: :username_input, value: state.form_data.username),
          UI.label("Password:"),
          UI.text_input(
            id: :password_input,
            value: state.form_data.password,
            password: true
          ),
          UI.button(id: :submit_button, label: "Submit"),
          case state.submitted do
            true -> UI.label("Submitted!")
            false -> nil
          end
        ]
        |> Enum.reject(&is_nil/1)
      end
    end
  end

  # Add a render/2 function for test compatibility
  # def render(state, _context) do
  #   view(state)
  # end

  # Add handle_event/3 for integration testing with Raxol.Test.Integration
  # This will be called by the test framework when events bubble from children.
  def handle_event(
        state,
        %Raxol.Core.Events.Event{type: :button_pressed},
        _opts
      ) do
    # Log submission (similar to update/2 logic)
    Raxol.Core.Runtime.Log.info(
      "Form received :button_pressed, processing as submit: #{inspect(state.form_data)}"
    )

    new_state = %{state | submitted: true}

    # For assert_parent_updated to pass, parent must dispatch an event of type :button_clicked.
    # Use a new :dispatch_to_self command that the integration framework will handle.
    {:update, new_state,
     [{:dispatch_to_self, %Raxol.Core.Events.Event{type: :button_clicked}}]}
  end

  # Catch-all for other events in integration test context if needed,
  # ensuring it doesn't conflict with the Application behaviour handle_event/1.
  # This specific arity is for the test framework.
  def handle_event(state, _event, _opts) do
    # Default pass-through for other events not specifically handled by Form in this context
    # Or simply :passthrough if state is guaranteed to be a component state map
    {:noreply, state, []}
  end
end
