defmodule MicrowavepropWeb.SubmitLiveTest do
  use MicrowavepropWeb.ConnCase, async: true

  import Phoenix.LiveViewTest

  alias Microwaveprop.Radio.Contact
  alias Microwaveprop.Repo
  alias Microwaveprop.Terrain.ElevationClient
  alias Microwaveprop.Weather.HrrrClient
  alias Microwaveprop.Weather.IemClient

  setup do
    Req.Test.stub(IemClient, fn conn ->
      case conn.request_path do
        "/cgi-bin/request/asos.py" -> Req.Test.text(conn, "#DEBUG,\nstation,valid,tmpf\n")
        _ -> Req.Test.json(conn, %{"profiles" => []})
      end
    end)

    Req.Test.stub(HrrrClient, fn conn ->
      Plug.Conn.send_resp(conn, 404, "not found")
    end)

    Req.Test.stub(ElevationClient, fn conn ->
      params = Plug.Conn.fetch_query_params(conn).query_params
      lat_count = params["latitude"] |> String.split(",") |> length()
      Req.Test.json(conn, %{"elevation" => List.duplicate(200.0, lat_count)})
    end)

    :ok
  end

  describe "mount" do
    test "renders the submission form", %{conn: conn} do
      {:ok, _lv, html} = live(conn, ~p"/submit")
      assert html =~ "Submit Contact"
      assert html =~ "Station 1"
      assert html =~ "Station 2"
      assert html =~ "Grid 1"
      assert html =~ "Grid 2"
      assert html =~ "Band"
      assert html =~ "Mode"
    end
  end

  describe "validate" do
    test "shows validation errors on change", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/submit")

      html =
        lv
        |> form("#contact-form", contact: %{station1: ""})
        |> render_change()

      assert html =~ "can&#39;t be blank"
    end
  end

  describe "csv upload" do
    test "renders CSV upload tab and sample download link", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/submit")

      html =
        lv
        |> element("[phx-value-tab=csv]")
        |> render_click()

      assert html =~ "Upload CSV"
      assert html =~ "/downloads/sample_contacts.csv"
      assert html =~ "Download sample CSV"
    end

    test "uploads valid CSV and shows preview with confirm button", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/submit")

      lv
      |> element("[phx-value-tab=csv]")
      |> render_click()

      csv_content =
        "station1,station2,grid1,grid2,band,mode,qso_timestamp\nW5XD,K5TR,EM12,EM00,10000,CW,2026-03-28T18:00:00Z\n"

      csv_input =
        file_input(lv, "#csv-upload-form", :csv, [
          %{name: "contacts.csv", content: csv_content, type: "text/csv"}
        ])

      render_upload(csv_input, "contacts.csv")

      html =
        lv
        |> form("#csv-upload-form", %{submitter_email: "test@example.com"})
        |> render_submit()

      assert html =~ "Review before submitting"
      assert html =~ "Looks good"
      # Nothing was inserted yet
      assert Repo.aggregate(Contact, :count) == 0

      lv
      |> element("button[phx-click=confirm_csv]")
      |> render_click()

      {path, _flash} = assert_redirect(lv)
      assert path =~ ~r"^/imports/[0-9a-f-]{36}$"
      # Oban runs inline, so by the time the redirect fires the chunk
      # worker has already inserted the contact.
      assert Repo.aggregate(Contact, :count) == 1
    end

    test "preview flags duplicates before confirmation", %{conn: conn} do
      # Seed an existing contact so the next upload is a duplicate of it.
      {:ok, _} =
        Microwaveprop.Radio.create_contact(%{
          "station1" => "W5XD",
          "station2" => "K5TR",
          "grid1" => "EM12",
          "grid2" => "EM00",
          "band" => "10000",
          "mode" => "CW",
          "qso_timestamp" => "2026-03-28T18:00:00Z",
          "submitter_email" => "seed@example.com"
        })

      {:ok, lv, _html} = live(conn, ~p"/submit")

      lv
      |> element("[phx-value-tab=csv]")
      |> render_click()

      csv_content =
        "station1,station2,grid1,grid2,band,mode,qso_timestamp\n" <>
          "W5XD,K5TR,EM12,EM00,10000,CW,2026-03-28T18:15:00Z\n"

      csv_input =
        file_input(lv, "#csv-upload-form", :csv, [
          %{name: "contacts.csv", content: csv_content, type: "text/csv"}
        ])

      render_upload(csv_input, "contacts.csv")

      html =
        lv
        |> form("#csv-upload-form", %{submitter_email: "test@example.com"})
        |> render_submit()

      assert html =~ "Duplicates"
      assert html =~ "Already in database"
      refute html =~ "Looks good"
    end

    test "preview shows refinements when upload extends an existing grid", %{conn: conn} do
      {:ok, existing} =
        Microwaveprop.Radio.create_contact(%{
          "station1" => "W5XD",
          "station2" => "K5TR",
          "grid1" => "EM12",
          "grid2" => "EM00",
          "band" => "10000",
          "mode" => "CW",
          "qso_timestamp" => "2026-03-28T18:00:00Z",
          "submitter_email" => "seed@example.com"
        })

      {:ok, lv, _html} = live(conn, ~p"/submit")

      lv
      |> element("[phx-value-tab=csv]")
      |> render_click()

      csv_content =
        "station1,station2,grid1,grid2,band,mode,qso_timestamp\n" <>
          "W5XD,K5TR,EM12KP37,EM00CD22,10000,CW,2026-03-28T18:10:00Z\n"

      csv_input =
        file_input(lv, "#csv-upload-form", :csv, [
          %{name: "contacts.csv", content: csv_content, type: "text/csv"}
        ])

      render_upload(csv_input, "contacts.csv")

      html =
        lv
        |> form("#csv-upload-form", %{submitter_email: "test@example.com"})
        |> render_submit()

      assert html =~ "Refinements"
      assert html =~ "EM12KP37"
      assert html =~ "refine 1 existing"

      lv
      |> element("button[phx-click=confirm_csv]")
      |> render_click()

      {path, _flash} = assert_redirect(lv)
      assert path =~ ~r"^/imports/[0-9a-f-]{36}$"
      assert Repo.aggregate(Contact, :count) == 1

      refreshed = Repo.reload(existing)
      assert refreshed.grid1 == "EM12KP37"
      assert refreshed.grid2 == "EM00CD22"
    end

    test "shows errors for invalid rows and still offers the confirm button", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/submit")

      lv
      |> element("[phx-value-tab=csv]")
      |> render_click()

      csv_content =
        "station1,station2,grid1,grid2,band,mode,qso_timestamp\n" <>
          "W5XD,K5TR,EM12,EM00,10000,CW,2026-03-28T18:00:00Z\n" <>
          ",,,,,,\n"

      csv_input =
        file_input(lv, "#csv-upload-form", :csv, [
          %{name: "contacts.csv", content: csv_content, type: "text/csv"}
        ])

      render_upload(csv_input, "contacts.csv")

      html =
        lv
        |> form("#csv-upload-form", %{submitter_email: "test@example.com"})
        |> render_submit()

      assert html =~ "Invalid rows"
      assert html =~ "Row 3"
      assert html =~ "Looks good"
    end

    test "cancel_csv clears the preview", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/submit")

      lv
      |> element("[phx-value-tab=csv]")
      |> render_click()

      csv_content =
        "station1,station2,grid1,grid2,band,mode,qso_timestamp\nW5XD,K5TR,EM12,EM00,10000,CW,2026-03-28T18:00:00Z\n"

      csv_input =
        file_input(lv, "#csv-upload-form", :csv, [
          %{name: "contacts.csv", content: csv_content, type: "text/csv"}
        ])

      render_upload(csv_input, "contacts.csv")

      lv
      |> form("#csv-upload-form", %{submitter_email: "test@example.com"})
      |> render_submit()

      html =
        lv
        |> element("button[phx-click=cancel_csv]")
        |> render_click()

      assert html =~ "Upload CSV"
      assert Repo.aggregate(Contact, :count) == 0
    end

    test "requires email for CSV upload", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/submit")

      lv
      |> element("[phx-value-tab=csv]")
      |> render_click()

      csv_content =
        "station1,station2,grid1,grid2,band,mode,qso_timestamp\nW5XD,K5TR,EM12,EM00,10000,CW,2026-03-28T18:00:00Z\n"

      csv_input =
        file_input(lv, "#csv-upload-form", :csv, [
          %{name: "contacts.csv", content: csv_content, type: "text/csv"}
        ])

      render_upload(csv_input, "contacts.csv")

      html =
        lv
        |> form("#csv-upload-form", %{submitter_email: ""})
        |> render_submit()

      assert html =~ "Email is required for CSV upload"
    end

    test "ADIF confirm redirects to /imports/:id", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/submit")

      lv
      |> element("[phx-value-tab=adif]")
      |> render_click()

      adif_content =
        "<CALL:4>K5TR" <>
          "<STATION_CALLSIGN:4>W5XD" <>
          "<GRIDSQUARE:4>EM00" <>
          "<MY_GRIDSQUARE:4>EM12" <>
          "<FREQ:5>10368" <>
          "<MODE:2>CW" <>
          "<QSO_DATE:8>20260328" <>
          "<TIME_ON:6>180000" <>
          "<EOR>"

      adif_input =
        file_input(lv, "#adif-upload-form", :adif, [
          %{name: "contacts.adi", content: adif_content, type: "application/octet-stream"}
        ])

      render_upload(adif_input, "contacts.adi")

      html =
        lv
        |> form("#adif-upload-form", %{submitter_email: "test@example.com"})
        |> render_submit()

      assert html =~ "Review before submitting"

      lv
      |> element("button[phx-click=confirm_csv]")
      |> render_click()

      {path, _flash} = assert_redirect(lv)
      assert path =~ ~r"^/imports/[0-9a-f-]{36}$"
      assert Repo.aggregate(Contact, :count) == 1
    end

    test "handles CSV with no data rows", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/submit")

      lv
      |> element("[phx-value-tab=csv]")
      |> render_click()

      csv_content = "station1,station2,grid1,grid2,band,mode,qso_timestamp\n"

      csv_input =
        file_input(lv, "#csv-upload-form", :csv, [
          %{name: "header_only.csv", content: csv_content, type: "text/csv"}
        ])

      render_upload(csv_input, "header_only.csv")

      html =
        lv
        |> form("#csv-upload-form", %{submitter_email: "test@example.com"})
        |> render_submit()

      assert html =~ "CSV file has no data rows"
    end
  end

  describe "save" do
    test "creates QSO and redirects on valid submit", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/submit")

      lv
      |> form("#contact-form",
        contact: %{
          station1: "W5XD",
          station2: "K5TR",
          qso_timestamp: "2026-03-28T18:00",
          mode: "CW",
          band: "1296",
          grid1: "EM12",
          grid2: "EM00",
          submitter_email: "test@example.com"
        }
      )
      |> render_submit()

      contact = Repo.one!(Contact)
      assert contact.station1 == "W5XD"
      assert contact.user_submitted == true
      assert contact.pos1["lat"]

      assert_redirect(lv, ~p"/contacts/#{contact.id}")
    end

    test "shows errors on invalid submit", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/submit")

      html =
        lv
        |> form("#contact-form", contact: %{station1: ""})
        |> render_submit()

      assert html =~ "can&#39;t be blank"
    end
  end
end
