defmodule BerrypodWeb.PageEditorHookTest do
  use BerrypodWeb.ConnCase, async: false

  import Phoenix.LiveViewTest
  import Berrypod.AccountsFixtures
  import Berrypod.ProductsFixtures

  alias Berrypod.Pages
  alias Berrypod.Pages.PageCache

  setup do
    PageCache.invalidate_all()
    user = user_fixture()
    {:ok, _} = Berrypod.Settings.set_site_live(true)

    provider_conn = provider_connection_fixture()

    product =
      product_fixture(%{
        provider_connection: provider_conn,
        title: "Test Product",
        category: "Test Category"
      })

    product_variant_fixture(%{product: product, title: "Standard", price: 1999})
    Berrypod.Products.recompute_cached_fields(product)

    %{user: user, product: product}
  end

  describe "non-admin cannot access edit mode" do
    test "editor sheet is not shown for non-admins", %{conn: conn} do
      {:ok, _view, html} = live(conn, "/")

      refute html =~ "editor-panel"
      refute html =~ "Edit page"
    end
  end

  describe "editor sheet visibility" do
    test "admin sees editor sheet with edit button", %{conn: conn, user: user} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, "/")

      assert has_element?(view, ".editor-panel")
      assert has_element?(view, "button.editor-fab")
    end

    test "non-admin does not see editor sheet", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/")

      refute has_element?(view, ".editor-panel")
      refute has_element?(view, "button.editor-fab")
    end
  end

  describe "entering and exiting edit mode" do
    setup %{conn: conn, user: user} do
      %{conn: log_in_user(conn, user)}
    end

    test "clicking edit button enters edit mode", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/")

      # Sheet starts collapsed
      assert has_element?(view, ".editor-panel[data-state='collapsed']")

      # Click edit button (the specific edit button class)
      view |> element(".editor-fab") |> render_click()

      # Now editing, sheet expanded
      assert has_element?(view, ".editor-panel[data-editing='true']")
      assert has_element?(view, ".editor-panel-content")
      assert has_element?(view, ".block-card")
    end

    test "sheet shows the page title when editing", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/")

      view |> element(".editor-fab") |> render_click()

      assert has_element?(view, ".editor-panel-page-title", "Home page")
    end

    test "sheet state changes when entering edit mode and collapsing", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/")

      # Starts collapsed
      assert has_element?(view, ".editor-panel[data-state='collapsed']")

      # Enter edit mode - expands to open
      view |> element(".editor-fab") |> render_click()
      assert has_element?(view, ".editor-panel[data-state='open']")

      # Collapse sheet (still in edit mode, just previewing)
      render_click(view, "editor_set_sheet_state", %{"state" => "collapsed"})

      assert has_element?(view, ".editor-panel[data-state='collapsed']")
      # Still in edit mode
      assert has_element?(view, ".editor-panel[data-editing='true']")
    end
  end

  describe "block manipulation in edit mode" do
    setup %{conn: conn, user: user} do
      %{conn: log_in_user(conn, user)}
    end

    test "move block down reorders the list", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/")

      # Enter edit mode
      view |> element(".editor-fab") |> render_click()

      # Home page default: hero is first block
      first_card = view |> element(".block-card:first-child")
      first_html = render(first_card)
      assert first_html =~ "Hero"

      # Get the hero block's ID and move it down
      blocks = Pages.get_page("home").blocks
      hero_id = List.first(blocks)["id"]

      view
      |> element("button[phx-click='editor_move_down'][phx-value-id='#{hero_id}']")
      |> render_click()

      # After move, hero is no longer the first card
      updated_first = view |> element(".block-card:first-child") |> render()
      refute updated_first =~ "Hero"
    end

    test "dirty indicator appears after changes", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/")

      # Enter edit mode
      view |> element(".editor-fab") |> render_click()

      refute has_element?(view, ".editor-panel-dirty")

      # Move a block to trigger dirty state
      blocks = Pages.get_page("home").blocks
      second_id = Enum.at(blocks, 1)["id"]

      view
      |> element("button[phx-click='editor_move_up'][phx-value-id='#{second_id}']")
      |> render_click()

      assert has_element?(view, ".editor-panel-dirty")
    end
  end

  describe "save and reset" do
    setup %{conn: conn, user: user} do
      %{conn: log_in_user(conn, user)}
    end

    test "save persists block changes", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/")

      # Enter edit mode
      view |> element(".editor-fab") |> render_click()

      # Move a block to make changes
      blocks = Pages.get_page("home").blocks
      original_first_type = List.first(blocks)["type"]
      second_id = Enum.at(blocks, 1)["id"]

      view
      |> element("button[phx-click='editor_move_up'][phx-value-id='#{second_id}']")
      |> render_click()

      # Save
      view |> element("button[phx-click='editor_save_all']") |> render_click()

      # Verify persistence
      updated = Pages.get_page("home")
      refute List.first(updated.blocks)["type"] == original_first_type
    end

    test "reset restores default blocks and is undoable", %{conn: conn} do
      # First, save a modified page (reverse block order)
      original = Pages.get_page("home")
      reordered = Enum.reverse(original.blocks)
      Pages.save_page("home", %{title: original.title, blocks: reordered})
      PageCache.invalidate_all()

      {:ok, view, _html} = live(conn, "/")

      # Enter edit mode
      view |> element(".editor-fab") |> render_click()

      # Get the first block type before reset (should be reversed, so last default)
      first_before_reset = view |> element(".block-card:first-child") |> render()

      # Reset
      view |> element("button[phx-click='editor_reset_defaults']") |> render_click()

      # First block should now be the default first (Hero)
      first_after_reset = view |> element(".block-card:first-child") |> render()
      assert first_after_reset =~ "Hero"
      refute first_after_reset == first_before_reset

      # Reset should be undoable
      refute has_element?(view, "button[phx-click='editor_undo'][disabled]")

      # Undo the reset
      view |> element("button[phx-click='editor_undo']") |> render_click()

      # Should be back to the reversed order
      first_after_undo = view |> element(".block-card:first-child") |> render()
      refute first_after_undo =~ "Hero"
    end
  end

  describe "undo and redo" do
    setup %{conn: conn, user: user} do
      %{conn: log_in_user(conn, user)}
    end

    test "undo reverts the last change", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/")

      # Enter edit mode
      view |> element(".editor-fab") |> render_click()

      blocks = Pages.get_page("home").blocks
      second_id = Enum.at(blocks, 1)["id"]

      view
      |> element("button[phx-click='editor_move_up'][phx-value-id='#{second_id}']")
      |> render_click()

      # After move_up, second block is now first
      first_html = view |> element(".block-card:first-child") |> render()
      refute first_html =~ "Hero"

      # Undo
      view |> element("button[phx-click='editor_undo']") |> render_click()

      # Hero should be back as first block
      restored_first = view |> element(".block-card:first-child") |> render()
      assert restored_first =~ "Hero"
    end

    test "redo restores an undone change", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/")

      # Enter edit mode
      view |> element(".editor-fab") |> render_click()

      blocks = Pages.get_page("home").blocks
      second_id = Enum.at(blocks, 1)["id"]

      view
      |> element("button[phx-click='editor_move_up'][phx-value-id='#{second_id}']")
      |> render_click()

      view |> element("button[phx-click='editor_undo']") |> render_click()
      view |> element("button[phx-click='editor_redo']") |> render_click()

      # After redo, hero should no longer be first
      first_html = view |> element(".block-card:first-child") |> render()
      refute first_html =~ "Hero"
    end

    test "history clears on save", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/")

      # Enter edit mode
      view |> element(".editor-fab") |> render_click()

      blocks = Pages.get_page("home").blocks
      second_id = Enum.at(blocks, 1)["id"]

      view
      |> element("button[phx-click='editor_move_up'][phx-value-id='#{second_id}']")
      |> render_click()

      view |> element("button[phx-click='editor_save_all']") |> render_click()

      # After save, undo should be disabled
      assert has_element?(view, "button[phx-click='editor_undo'][disabled]")
    end

    test "undo/redo buttons reflect stack state", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/")

      # Enter edit mode
      view |> element(".editor-fab") |> render_click()

      # Initially both disabled
      assert has_element?(view, "button[phx-click='editor_undo'][disabled]")
      assert has_element?(view, "button[phx-click='editor_redo'][disabled]")

      # Make a change
      blocks = Pages.get_page("home").blocks
      second_id = Enum.at(blocks, 1)["id"]

      view
      |> element("button[phx-click='editor_move_up'][phx-value-id='#{second_id}']")
      |> render_click()

      # Undo enabled, redo still disabled
      refute has_element?(view, "button[phx-click='editor_undo'][disabled]")
      assert has_element?(view, "button[phx-click='editor_redo'][disabled]")
    end
  end

  describe "content pages" do
    setup %{conn: conn, user: user} do
      %{conn: log_in_user(conn, user)}
    end

    test "editing works on about page", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/about")

      # Editor sheet visible for admin
      assert has_element?(view, ".editor-panel")

      # Enter edit mode
      view |> element(".editor-fab") |> render_click()

      assert has_element?(view, ".editor-panel-content")
      assert has_element?(view, ".editor-panel-page-title", "About")
      assert has_element?(view, ".block-card")
    end
  end
end
