defmodule Raxol.Terminal.ANSI.Sequences.Cursor do
  @moduledoc """
  ANSI Cursor Sequence Handler.

  Handles parsing and application of ANSI cursor control sequences,
  including movement, position saving/restoring, and visibility.
  """

  alias Raxol.Terminal.Emulator
  alias Raxol.Terminal.ScreenBuffer

  @doc """
  Move cursor to absolute position.

  ## Parameters

  * `emulator` - The terminal emulator state
  * `row` - Row to move to (1-indexed)
  * `col` - Column to move to (1-indexed)

  ## Returns

  Updated emulator state
  """
  def move_cursor(emulator, row, col) do
    # Convert 1-indexed ANSI coordinates to 0-indexed internal coordinates
    row = max(0, row - 1)
    col = max(0, col - 1)

    # Ensure coordinates are within bounds
    active_buffer = Emulator.get_screen_buffer(emulator)
    height = ScreenBuffer.get_height(active_buffer)
    width = ScreenBuffer.get_width(active_buffer)

    row = min(row, height - 1)
    col = min(col, width - 1)

    # Update cursor position (correctly update nested cursor struct)
    %{emulator | cursor: %{emulator.cursor | position: {row, col}}}
  end

  @doc """
  Move cursor up by specified number of rows.

  ## Parameters

  * `emulator` - The terminal emulator state
  * `n` - Number of rows to move up

  ## Returns

  Updated emulator state
  """
  def move_cursor_up(emulator, n) do
    n =
      case n <= 0 do
        true -> 1
        false -> n
      end

    {cur_x, cur_y} = emulator.cursor.position
    new_y = max(0, cur_y - n)
    %{emulator | cursor: %{emulator.cursor | position: {cur_x, new_y}}}
  end

  @doc """
  Move cursor down by specified number of rows.

  ## Parameters

  * `emulator` - The terminal emulator state
  * `n` - Number of rows to move down

  ## Returns

  Updated emulator state
  """
  def move_cursor_down(emulator, n) do
    n =
      case n <= 0 do
        true -> 1
        false -> n
      end

    active_buffer = Emulator.get_screen_buffer(emulator)
    height = ScreenBuffer.get_height(active_buffer)
    {cur_x, cur_y} = emulator.cursor.position
    new_y = min(cur_y + n, height - 1)
    %{emulator | cursor: %{emulator.cursor | position: {cur_x, new_y}}}
  end

  @doc """
  Move cursor forward by specified number of columns.

  ## Parameters

  * `emulator` - The terminal emulator state
  * `n` - Number of columns to move forward

  ## Returns

  Updated emulator state
  """
  def move_cursor_forward(emulator, n) do
    n =
      case n <= 0 do
        true -> 1
        false -> n
      end

    active_buffer = Emulator.get_screen_buffer(emulator)
    width = ScreenBuffer.get_width(active_buffer)
    {cur_x, cur_y} = emulator.cursor.position
    new_x = min(cur_x + n, width - 1)
    %{emulator | cursor: %{emulator.cursor | position: {new_x, cur_y}}}
  end

  @doc """
  Move cursor backward by specified number of columns.

  ## Parameters

  * `emulator` - The terminal emulator state
  * `n` - Number of columns to move backward

  ## Returns

  Updated emulator state
  """
  def move_cursor_backward(emulator, n) do
    n =
      case n <= 0 do
        true -> 1
        false -> n
      end

    {cur_x, cur_y} = emulator.cursor.position
    new_x = max(0, cur_x - n)
    %{emulator | cursor: %{emulator.cursor | position: {new_x, cur_y}}}
  end

  @doc """
  Save current cursor position.

  ## Parameters

  * `emulator` - The terminal emulator state

  ## Returns

  Updated emulator state with saved cursor position
  """
  def save_cursor_position(emulator) do
    %{
      emulator
      | cursor: %{emulator.cursor | saved_position: emulator.cursor.position}
    }
  end

  @doc """
  Restore previously saved cursor position.

  ## Parameters

  * `emulator` - The terminal emulator state

  ## Returns

  Updated emulator state with restored cursor position
  """
  def restore_cursor_position(emulator) do
    case emulator.cursor.saved_position do
      {x, y} -> %{emulator | cursor: %{emulator.cursor | position: {x, y}}}
      _ -> emulator
    end
  end

  @doc """
  Set cursor visibility.

  ## Parameters

  * `emulator` - The terminal emulator state
  * `visible` - Boolean indicating visibility

  ## Returns

  Updated emulator state
  """
  def set_cursor_visibility(emulator, visible) do
    %{emulator | cursor_visible: visible}
  end
end
