defmodule BerrypodWeb.Admin.OrderShow do
  use BerrypodWeb, :live_view

  alias Berrypod.{ActivityLog, Mailer, Orders}
  alias Berrypod.Cart

  @impl true
  def mount(%{"id" => id}, _session, socket) do
    case Orders.get_order(id) do
      nil ->
        socket =
          socket
          |> put_flash(:error, "Order not found")
          |> push_navigate(to: ~p"/admin/orders")

        {:ok, socket}

      order ->
        if connected?(socket), do: ActivityLog.subscribe(order.id)

        timeline = ActivityLog.list_for_order(order.id)

        socket =
          socket
          |> assign(:page_title, order.order_number)
          |> assign(:order, order)
          |> assign(:timeline, timeline)
          |> assign(:email_configured, Mailer.email_configured?())

        {:ok, socket}
    end
  end

  @impl true
  def handle_info({:new_activity, entry}, socket) do
    {:noreply, assign(socket, :timeline, socket.assigns.timeline ++ [entry])}
  end

  @impl true
  def render(assigns) do
    ~H"""
    <.header>
      <.link navigate={~p"/admin/orders"} class="admin-back-link">
        &larr; Orders
      </.link>
      <div class="admin-product-header">
        <span class="admin-product-title">{@order.order_number}</span>
        <.status_badge status={@order.payment_status} />
      </div>
    </.header>

    <div :if={!@email_configured} class="admin-callout-warning admin-card-spaced">
      <div class="admin-callout-warning-body">
        <span class="admin-callout-warning-icon">
          <.icon name="hero-exclamation-triangle" class="size-5" />
        </span>
        <div>
          <p class="admin-callout-warning-title">
            Order confirmation emails aren't being sent
          </p>
          <p class="admin-callout-warning-desc">
            Set up an email provider to send order confirmations and shipping updates automatically.
            <.link navigate={~p"/admin/settings/email"} class="admin-link">
              Set up email &rarr;
            </.link>
          </p>
        </div>
      </div>
    </div>

    <div class="admin-grid order-detail-grid">
      <%!-- order info --%>
      <div class="admin-card">
        <div class="admin-card-body">
          <h3 class="admin-card-title">Order details</h3>
          <.list>
            <:item title="Date">{format_date(@order.inserted_at)}</:item>
            <:item title="Customer">{@order.customer_email || "—"}</:item>
            <:item title="Payment status">
              <.status_badge status={@order.payment_status} />
            </:item>
            <:item :if={@order.stripe_payment_intent_id} title="Stripe payment">
              <code class="admin-code-sm">{@order.stripe_payment_intent_id}</code>
            </:item>
            <:item title="Currency">{String.upcase(@order.currency)}</:item>
          </.list>
        </div>
      </div>

      <%!-- shipping address --%>
      <div class="admin-card">
        <div class="admin-card-body">
          <h3 class="admin-card-title">Shipping address</h3>
          <%= if @order.shipping_address != %{} do %>
            <.list>
              <:item :if={@order.shipping_address["name"]} title="Name">
                {@order.shipping_address["name"]}
              </:item>
              <:item :if={@order.shipping_address["line1"]} title="Address">
                {@order.shipping_address["line1"]}
                <span :if={@order.shipping_address["line2"]}>
                  <br />{@order.shipping_address["line2"]}
                </span>
              </:item>
              <:item :if={@order.shipping_address["city"]} title="City">
                {@order.shipping_address["city"]}
              </:item>
              <:item :if={@order.shipping_address["state"] not in [nil, ""]} title="State">
                {@order.shipping_address["state"]}
              </:item>
              <:item :if={@order.shipping_address["postal_code"]} title="Postcode">
                {@order.shipping_address["postal_code"]}
              </:item>
              <:item :if={@order.shipping_address["country"]} title="Country">
                {@order.shipping_address["country"]}
              </:item>
            </.list>
          <% else %>
            <p class="admin-section-desc admin-section-desc-flush">No shipping address provided</p>
          <% end %>
        </div>
      </div>
    </div>

    <%!-- timeline --%>
    <div class="admin-card admin-card-spaced">
      <div class="admin-card-body">
        <div class="admin-row admin-row-between">
          <h3 class="admin-card-title">Timeline</h3>
          <.fulfilment_badge status={@order.fulfilment_status} />
        </div>
        <div class="admin-row order-timeline-actions">
          <button
            :if={can_submit?(@order)}
            phx-click="submit_to_provider"
            class="admin-btn admin-btn-primary admin-btn-sm"
          >
            <.icon name="hero-paper-airplane-mini" class="size-4" />
            {if @order.fulfilment_status == "failed",
              do: "Retry submission",
              else: "Submit to provider"}
          </button>
          <button
            :if={can_refresh?(@order)}
            phx-click="refresh_status"
            class="admin-btn admin-btn-ghost admin-btn-sm"
          >
            <.icon name="hero-arrow-path-mini" class="size-4" /> Refresh status
          </button>
        </div>
        <div
          :if={@order.tracking_number not in [nil, ""]}
          class="admin-row order-tracking"
        >
          <span class="admin-text-secondary"><.icon name="hero-truck-mini" class="size-4" /></span>
          <span class="admin-text-medium">{@order.tracking_number}</span>
          <.external_link
            :if={@order.tracking_url not in [nil, ""]}
            href={@order.tracking_url}
            class="admin-link"
          >
            Track shipment
          </.external_link>
        </div>
        <.order_timeline entries={@timeline} />
      </div>
    </div>

    <%!-- line items --%>
    <div class="admin-card admin-card-spaced">
      <div class="admin-card-body">
        <h3 class="admin-card-title">Items</h3>
        <table class="admin-table admin-table-zebra">
          <thead>
            <tr>
              <th>Product</th>
              <th>Variant</th>
              <th class="admin-cell-end">Qty</th>
              <th class="admin-cell-end">Unit price</th>
              <th class="admin-cell-end">Total</th>
            </tr>
          </thead>
          <tbody>
            <tr :for={item <- @order.items}>
              <td>{item.product_name}</td>
              <td>{item.variant_title}</td>
              <td class="admin-cell-numeric">{item.quantity}</td>
              <td class="admin-cell-numeric">{Cart.format_price(item.unit_price)}</td>
              <td class="admin-cell-numeric">{Cart.format_price(item.unit_price * item.quantity)}</td>
            </tr>
          </tbody>
          <tfoot>
            <tr>
              <td colspan="4" class="admin-cell-end admin-text-medium">Subtotal</td>
              <td class="admin-cell-end admin-text-medium">{Cart.format_price(@order.subtotal)}</td>
            </tr>
            <tr class="order-total-row">
              <td colspan="4" class="admin-cell-end admin-text-bold">Total</td>
              <td class="admin-cell-end admin-text-bold">{Cart.format_price(@order.total)}</td>
            </tr>
          </tfoot>
        </table>
      </div>
    </div>
    """
  end

  @impl true
  def handle_event("submit_to_provider", _params, socket) do
    order = socket.assigns.order

    case Orders.submit_to_provider(order) do
      {:ok, updated} ->
        socket =
          socket
          |> assign(:order, updated)
          |> put_flash(:info, "Order submitted to provider")

        {:noreply, socket}

      {:error, _reason} ->
        order = Orders.get_order(order.id)

        socket =
          socket
          |> assign(:order, order)
          |> put_flash(:error, order.fulfilment_error || "Submission failed")

        {:noreply, socket}
    end
  end

  def handle_event("refresh_status", _params, socket) do
    order = socket.assigns.order

    case Orders.refresh_fulfilment_status(order) do
      {:ok, updated} ->
        socket =
          socket
          |> assign(:order, updated)
          |> put_flash(:info, "Status refreshed")

        {:noreply, socket}

      {:error, reason} ->
        {:noreply, put_flash(socket, :error, "Failed to refresh: #{inspect(reason)}")}
    end
  end

  # ── Components ──

  defp order_timeline(assigns) do
    ~H"""
    <div :if={@entries == []} class="admin-section-desc order-timeline-empty">
      No activity recorded yet.
    </div>
    <ol :if={@entries != []} class="admin-timeline" id="order-timeline">
      <li :for={entry <- @entries} class="admin-timeline-item">
        <div class={["admin-timeline-dot", timeline_dot_class(entry.level)]}></div>
        <div class="admin-timeline-content">
          <p class="admin-timeline-message">{entry.message}</p>
          <time class="admin-timeline-time" datetime={DateTime.to_iso8601(entry.occurred_at)}>
            {format_timeline_time(entry.occurred_at)}
          </time>
        </div>
      </li>
    </ol>
    """
  end

  defp timeline_dot_class("error"), do: "admin-timeline-dot-error"
  defp timeline_dot_class("warning"), do: "admin-timeline-dot-warning"
  defp timeline_dot_class(_), do: "admin-timeline-dot-info"

  defp format_timeline_time(datetime) do
    today = Date.utc_today()
    event_date = DateTime.to_date(datetime)
    diff_days = Date.diff(today, event_date)

    cond do
      diff_days == 0 -> Calendar.strftime(datetime, "%H:%M")
      diff_days < 7 -> Calendar.strftime(datetime, "%d %b %H:%M")
      true -> Calendar.strftime(datetime, "%d %b %Y")
    end
  end

  defp can_submit?(order) do
    order.payment_status == "paid" and order.fulfilment_status in ["unfulfilled", "failed"]
  end

  defp can_refresh?(order) do
    not is_nil(order.provider_order_id) and
      order.fulfilment_status in ["submitted", "processing", "shipped"]
  end

  defp fulfilment_badge(assigns) do
    {color, icon} =
      case assigns.status do
        "submitted" -> {"admin-status-pill-blue", "hero-paper-airplane-mini"}
        "processing" -> {"admin-status-pill-amber", "hero-cog-6-tooth-mini"}
        "shipped" -> {"admin-status-pill-purple", "hero-truck-mini"}
        "delivered" -> {"admin-status-pill-green", "hero-check-circle-mini"}
        "failed" -> {"admin-status-pill-red", "hero-x-circle-mini"}
        "cancelled" -> {"admin-status-pill-zinc", "hero-no-symbol-mini"}
        _ -> {"admin-status-pill-zinc", "hero-minus-circle-mini"}
      end

    assigns = assign(assigns, color: color, icon: icon)

    ~H"""
    <span class={["admin-status-pill", @color]}>
      <.icon name={@icon} class="size-3" /> {@status}
    </span>
    """
  end

  defp status_badge(assigns) do
    {color, icon} =
      case assigns.status do
        "paid" -> {"admin-status-pill-green", "hero-check-circle-mini"}
        "pending" -> {"admin-status-pill-amber", "hero-clock-mini"}
        "failed" -> {"admin-status-pill-red", "hero-x-circle-mini"}
        "refunded" -> {"admin-status-pill-zinc", "hero-arrow-uturn-left-mini"}
        _ -> {"admin-status-pill-zinc", "hero-question-mark-circle-mini"}
      end

    assigns = assign(assigns, color: color, icon: icon)

    ~H"""
    <span class={["admin-status-pill", @color]}>
      <.icon name={@icon} class="size-3" /> {@status}
    </span>
    """
  end

  defp format_date(datetime) do
    Calendar.strftime(datetime, "%d %b %Y %H:%M")
  end
end
