defmodule ToweropsWeb.Admin.AuditLive.Index do
  @moduledoc """
  Admin interface for viewing and searching audit logs.
  Provides comprehensive search, filtering, and export capabilities.
  """
  use ToweropsWeb, :live_view

  import Ecto.Query

  alias Towerops.Repo

  @impl true
  def mount(_params, _session, socket) do
    {:ok,
     socket
     |> assign(:page_title, "Audit Logs")
     |> assign(:search_email, "")
     |> assign(:search_action, "")
     |> assign(:date_from, "")
     |> assign(:date_to, "")
     |> assign(:page, 1)
     |> assign(:per_page, 50)
     |> load_audit_logs()}
  end

  @impl true
  def handle_event("search", params, socket) do
    {:noreply,
     socket
     |> assign(:search_email, params["email"] || "")
     |> assign(:search_action, params["action"] || "")
     |> assign(:date_from, params["date_from"] || "")
     |> assign(:date_to, params["date_to"] || "")
     |> assign(:page, 1)
     |> load_audit_logs()}
  end

  @impl true
  def handle_event("clear_filters", _params, socket) do
    {:noreply,
     socket
     |> assign(:search_email, "")
     |> assign(:search_action, "")
     |> assign(:date_from, "")
     |> assign(:date_to, "")
     |> assign(:page, 1)
     |> load_audit_logs()}
  end

  @impl true
  def handle_event("export", _params, socket) do
    # Generate CSV export
    logs = fetch_audit_logs(socket, limit: :all)
    csv_content = generate_csv(logs)

    {:noreply,
     push_event(socket, "download", %{
       filename: "audit-logs-#{Date.utc_today()}.csv",
       content: csv_content,
       mime_type: "text/csv"
     })}
  end

  @impl true
  def handle_event("next_page", _params, socket) do
    {:noreply,
     socket
     |> assign(:page, socket.assigns.page + 1)
     |> load_audit_logs()}
  end

  @impl true
  def handle_event("prev_page", _params, socket) do
    {:noreply,
     socket
     |> assign(:page, max(1, socket.assigns.page - 1))
     |> load_audit_logs()}
  end

  @impl true
  def render(assigns) do
    ~H"""
    <Layouts.admin flash={@flash} timezone={@current_scope.user.timezone}>
      <div class="border-b border-gray-200 pb-5 dark:border-white/5">
        <h1 class="text-3xl font-semibold tracking-tight text-gray-900 dark:text-white">
          Audit Logs
        </h1>
        <p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
          View and search all system audit logs. Records are retained for 3 years.
        </p>
      </div>
      
    <!-- Search Filters -->
      <div class="mt-8 bg-white dark:bg-gray-900 shadow rounded-lg p-6">
        <form phx-submit="search" class="space-y-4">
          <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
            <div>
              <label for="email" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
                User Email
              </label>
              <input
                type="text"
                name="email"
                id="email"
                value={@search_email}
                placeholder="user@example.com"
                class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-800 dark:border-gray-600 dark:text-white"
              />
            </div>

            <div>
              <label for="action" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
                Action
              </label>
              <select
                name="action"
                id="action"
                class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-800 dark:border-gray-600 dark:text-white"
              >
                <option value="">All Actions</option>
                <%= for action <- available_actions() do %>
                  <option value={action} selected={@search_action == action}>
                    {format_action(action)}
                  </option>
                <% end %>
              </select>
            </div>

            <div>
              <label
                for="date_from"
                class="block text-sm font-medium text-gray-700 dark:text-gray-300"
              >
                From Date
              </label>
              <input
                type="date"
                name="date_from"
                id="date_from"
                value={@date_from}
                class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-800 dark:border-gray-600 dark:text-white"
              />
            </div>

            <div>
              <label for="date_to" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
                To Date
              </label>
              <input
                type="date"
                name="date_to"
                id="date_to"
                value={@date_to}
                class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-800 dark:border-gray-600 dark:text-white"
              />
            </div>
          </div>

          <div class="flex gap-3">
            <button
              type="submit"
              class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
            >
              <.icon name="hero-magnifying-glass" class="h-4 w-4 mr-2" /> Search
            </button>
            <button
              type="button"
              phx-click="clear_filters"
              class="inline-flex items-center px-4 py-2 border border-gray-300 dark:border-gray-600 text-sm font-medium rounded-md text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
            >
              <.icon name="hero-x-mark" class="h-4 w-4 mr-2" /> Clear
            </button>
            <button
              type="button"
              phx-click="export"
              class="inline-flex items-center px-4 py-2 border border-gray-300 dark:border-gray-600 text-sm font-medium rounded-md text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
            >
              <.icon name="hero-arrow-down-tray" class="h-4 w-4 mr-2" /> Export CSV
            </button>
          </div>
        </form>
      </div>
      
    <!-- Results -->
      <div class="mt-8">
        <%= if Enum.empty?(@audit_logs) do %>
          <div class="text-center py-12 bg-white dark:bg-gray-900 rounded-lg shadow">
            <.icon name="hero-document-text" class="mx-auto h-12 w-12 text-gray-400" />
            <h3 class="mt-2 text-sm font-medium text-gray-900 dark:text-white">
              No audit logs found
            </h3>
            <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
              Try adjusting your search filters.
            </p>
          </div>
        <% else %>
          <div class="bg-white dark:bg-gray-900 shadow rounded-lg overflow-hidden">
            <div class="overflow-x-auto">
              <table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
                <thead class="bg-gray-50 dark:bg-gray-800">
                  <tr>
                    <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
                      Timestamp
                    </th>
                    <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
                      Action
                    </th>
                    <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
                      Actor
                    </th>
                    <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
                      Target User
                    </th>
                    <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
                      IP Address
                    </th>
                    <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
                      Details
                    </th>
                  </tr>
                </thead>
                <tbody class="divide-y divide-gray-200 dark:divide-gray-700">
                  <%= for log <- @audit_logs do %>
                    <tr class="hover:bg-gray-50 dark:hover:bg-gray-800">
                      <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-white">
                        {ToweropsWeb.TimeHelpers.format_datetime(
                          log.inserted_at,
                          @current_scope.timezone,
                          @current_scope.time_format
                        )}
                      </td>
                      <td class="px-6 py-4 whitespace-nowrap">
                        <span class={[
                          "inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ring-1 ring-inset",
                          action_badge_class(log.action)
                        ]}>
                          {format_action(log.action)}
                        </span>
                      </td>
                      <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">
                        <%= if log.superuser do %>
                          {log.superuser.email}
                        <% else %>
                          <span class="text-gray-400">System</span>
                        <% end %>
                      </td>
                      <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">
                        <%= if log.target_user do %>
                          {log.target_user.email}
                        <% else %>
                          <span class="text-gray-400">-</span>
                        <% end %>
                      </td>
                      <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">
                        {log.ip_address || "-"}
                      </td>
                      <td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">
                        <%= if log.request_path do %>
                          <div class="text-xs">
                            <code class="bg-gray-100 dark:bg-gray-800 px-1 rounded">
                              {log.request_path}
                            </code>
                          </div>
                        <% end %>
                        <%= if log.metadata && map_size(log.metadata) > 0 do %>
                          <details class="mt-1">
                            <summary class="cursor-pointer text-xs text-blue-600 dark:text-blue-400 hover:underline">
                              Metadata
                            </summary>
                            <pre class="mt-1 text-xs bg-gray-100 dark:bg-gray-800 p-2 rounded overflow-x-auto max-w-md">
                              {Jason.encode!(log.metadata, pretty: true)}
                            </pre>
                          </details>
                        <% end %>
                      </td>
                    </tr>
                  <% end %>
                </tbody>
              </table>
            </div>
            
    <!-- Pagination -->
            <div class="bg-gray-50 dark:bg-gray-800 px-6 py-4 flex items-center justify-between border-t border-gray-200 dark:border-gray-700">
              <div class="text-sm text-gray-700 dark:text-gray-300">
                Page {@page} • Showing {length(@audit_logs)} records
              </div>
              <div class="flex gap-2">
                <button
                  type="button"
                  phx-click="prev_page"
                  disabled={@page == 1}
                  class="relative inline-flex items-center px-4 py-2 border border-gray-300 dark:border-gray-600 text-sm font-medium rounded-md text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
                >
                  Previous
                </button>
                <button
                  type="button"
                  phx-click="next_page"
                  disabled={length(@audit_logs) < @per_page}
                  class="relative inline-flex items-center px-4 py-2 border border-gray-300 dark:border-gray-600 text-sm font-medium rounded-md text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
                >
                  Next
                </button>
              </div>
            </div>
          </div>
        <% end %>
      </div>
    </Layouts.admin>
    """
  end

  # Private functions

  defp load_audit_logs(socket) do
    logs = fetch_audit_logs(socket, limit: socket.assigns.per_page)
    assign(socket, :audit_logs, logs)
  end

  defp fetch_audit_logs(socket, opts) do
    limit = Keyword.get(opts, :limit, socket.assigns.per_page)
    offset = (socket.assigns.page - 1) * socket.assigns.per_page

    query =
      from(a in Towerops.Admin.AuditLog,
        preload: [:superuser, :target_user],
        order_by: [desc: a.inserted_at]
      )

    query = apply_filters(query, socket)

    if limit == :all do
      Repo.all(query)
    else
      query
      |> limit(^limit)
      |> offset(^offset)
      |> Repo.all()
    end
  end

  defp apply_filters(query, socket) do
    query
    |> filter_by_email(socket.assigns.search_email)
    |> filter_by_action(socket.assigns.search_action)
    |> filter_by_date_range(socket.assigns.date_from, socket.assigns.date_to)
  end

  defp filter_by_email(query, ""), do: query

  defp filter_by_email(query, email) do
    from(a in query,
      left_join: su in assoc(a, :superuser),
      left_join: tu in assoc(a, :target_user),
      where: ilike(su.email, ^"%#{email}%") or ilike(tu.email, ^"%#{email}%")
    )
  end

  defp filter_by_action(query, ""), do: query
  defp filter_by_action(query, action), do: where(query, [a], a.action == ^action)

  defp filter_by_date_range(query, "", ""), do: query

  defp filter_by_date_range(query, from_date, to_date) do
    query =
      if from_date == "" do
        query
      else
        {:ok, from_datetime} = NaiveDateTime.new(Date.from_iso8601!(from_date), ~T[00:00:00])
        where(query, [a], a.inserted_at >= ^from_datetime)
      end

    if to_date == "" do
      query
    else
      {:ok, to_datetime} = NaiveDateTime.new(Date.from_iso8601!(to_date), ~T[23:59:59])
      where(query, [a], a.inserted_at <= ^to_datetime)
    end
  end

  defp generate_csv(logs) do
    headers = "Timestamp,Action,Actor Email,Target User Email,IP Address,Request Path,Metadata\n"

    rows =
      Enum.map_join(logs, "\n", fn log ->
        Enum.map_join(
          [
            Calendar.strftime(log.inserted_at, "%Y-%m-%d %H:%M:%S"),
            log.action,
            if(log.superuser, do: log.superuser.email, else: "System"),
            if(log.target_user, do: log.target_user.email, else: ""),
            log.ip_address || "",
            log.request_path || "",
            Jason.encode!(log.metadata || %{})
          ],
          ",",
          &escape_csv_field/1
        )
      end)

    headers <> rows
  end

  defp escape_csv_field(field) when is_binary(field) do
    if String.contains?(field, [",", "\"", "\n"]) do
      "\"#{String.replace(field, "\"", "\"\"")}\""
    else
      field
    end
  end

  defp escape_csv_field(_), do: ""

  defp available_actions do
    [
      "impersonate_start",
      "impersonate_end",
      "user_delete",
      "org_delete",
      "user_data_viewed",
      "user_data_exported",
      "user_profile_updated",
      "org_data_accessed",
      "device_created",
      "device_updated",
      "device_deleted",
      "monitoring_data_queried",
      "failed_access_attempt",
      "privilege_escalation"
    ]
  end

  defp action_badge_class(action) do
    action
    |> audit_action_category()
    |> audit_badge_class_for_category()
  end

  defp audit_action_category(action) do
    cond do
      action in ["user_data_exported", "device_created"] -> :success
      action == "device_updated" -> :warning
      action in ["device_deleted", "failed_access_attempt"] -> :danger
      action in ["impersonate_start", "impersonate_end"] -> :impersonation
      action == "user_data_viewed" -> :info
      true -> :default
    end
  end

  defp audit_badge_class_for_category(category) do
    case category do
      :success -> "bg-green-50 text-green-700 ring-green-600/20"
      :warning -> "bg-yellow-50 text-yellow-700 ring-yellow-600/20"
      :danger -> "bg-red-50 text-red-700 ring-red-600/20"
      :impersonation -> "bg-orange-50 text-orange-700 ring-orange-600/20"
      :info -> "bg-blue-50 text-blue-700 ring-blue-600/20"
      :default -> "bg-gray-50 text-gray-700 ring-gray-600/20"
    end
  end

  defp format_action(action) do
    action
    |> String.replace("_", " ")
    |> String.capitalize()
  end
end
