require "test_helper"
require "roo"
require "tempfile"

class EntriesControllerTest < ActionDispatch::IntegrationTest
  setup do
    @entry = entries(:one)
    @user = users(:admin_user)
  end

  # INDEX tests
  test "should get index" do
    get entries_url
    assert_response :success
  end

  test "should filter by language" do
    get entries_url, params: { language: "fi" }
    assert_response :success
    assert_select "input[type=hidden][name='language'][value='fi']"
  end

  test "should filter by category" do
    get entries_url, params: { category: "word" }
    assert_response :success
    assert_select "input[type=hidden][name='category'][value='word']"
  end

  test "should search with query" do
    get entries_url, params: { q: "test" }
    assert_response :success
    assert_select "input[name='q'][value='test']"
  end

  test "should filter by starts_with" do
    get entries_url, params: { starts_with: "a" }
    assert_response :success
    assert_select "input[type=hidden][name='starts_with'][value='a']"
  end

  test "should paginate results" do
    get entries_url, params: { page: 2 }
    assert_response :success
    assert_not_nil assigns(:pagy)
    assert_select "div", text: /Displaying/i
  end

  test "should handle invalid language code" do
    get entries_url, params: { language: "invalid" }
    assert_response :success
    assert_select "input[name='language']", count: 0
  end

  test "should respond to turbo_stream" do
    get entries_url, as: :turbo_stream
    assert_response :success
  end

  test "should only show active entries in index" do
    # Create a requested entry that should not appear
    requested_entry = Entry.create!(
      fi: "Requested",
      category: :word,
      status: :requested,
      requested_by: @user
    )

    get entries_url
    assert_response :success
    assert_select "td", text: requested_entry.fi, count: 0
  end

  # SHOW tests
  test "should show entry" do
    get entry_url(@entry)
    assert_response :success
  end

  test "should show entry with comments" do
    get entry_url(@entry)
    assert_response :success
    assert_select "p", text: @entry.fi
  end

  # EDIT tests
  test "should get edit" do
    get edit_entry_url(@entry)
    assert_response :success
  end

  # UPDATE tests
  test "should update entry" do
    patch entry_url(@entry), params: {
      entry: {
        fi: "Updated Finnish",
        en: "Updated English",
        category: "word"
      }
    }
    assert_redirected_to entry_url(@entry)
    @entry.reload
    assert_equal "Updated Finnish", @entry.fi
  end

  test "should not update entry with invalid data" do
    patch entry_url(@entry), params: {
      entry: {
        fi: "",
        en: "",
        sv: "",
        no: "",
        ru: "",
        de: ""
      }
    }
    assert_response :unprocessable_entity
  end

  test "should update entry category" do
    patch entry_url(@entry), params: {
      entry: { category: "phrase" }
    }
    assert_redirected_to entry_url(@entry)
    @entry.reload
    assert_equal "phrase", @entry.category
  end

  # DOWNLOAD tests
  test "should download xlsx" do
    get download_entries_url(format: :xlsx)
    assert_response :success
    assert_equal "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                 response.media_type
  end

  test "should include active entries in xlsx" do
    unique_entry = Entry.create!(
      fi: "UniqueActiveEntry123",
      category: :word,
      status: :active
    )

    get download_entries_url(format: :xlsx)
    assert_response :success

    Tempfile.create([ "entries", ".xlsx" ]) do |file|
      file.binmode
      file.write(response.body)
      file.flush

      sheet = Roo::Excelx.new(file.path).sheet(0)
      cell_values = sheet.to_a.flatten.compact
      assert_includes cell_values, unique_entry.fi
    end
  end

  # Statistics tests
  test "should calculate entry statistics" do
    get entries_url
    assert_response :success
    assert_select "div", text: /entries/i
    assert_select "div", text: /% complete/i
  end

  test "should calculate language completion" do
    get entries_url
    assert_response :success
    assert_select "div", text: /% complete/i
  end

  # Language ordering tests
  test "should prioritize selected language in display" do
    get entries_url, params: { language: "fi" }
    assert_response :success
    assert_select "th span", text: "FI", count: 1
  end
end
