defmodule ToweropsWeb.Router do
  @moduledoc false

  use ToweropsWeb, :router
  use Honeybadger.Plug

  import Oban.Web.Router
  import Phoenix.LiveDashboard.Router
  import ToweropsWeb.UserAuth

  alias ToweropsWeb.Api.V1
  alias ToweropsWeb.Plugs.RateLimit

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, html: {ToweropsWeb.Layouts, :root}
    plug :protect_from_forgery

    plug :put_secure_browser_headers, %{
      # Content-Security-Policy for LiveView applications
      # Note: 'unsafe-inline' for scripts is required for LiveView to function
      # WebSocket connection required for LiveView real-time updates
      "content-security-policy" =>
        "default-src 'self'; " <>
          "script-src 'self' 'unsafe-inline' 'unsafe-eval'; " <>
          "style-src 'self' 'unsafe-inline'; " <>
          "img-src 'self' data: https:; " <>
          "font-src 'self' data:; " <>
          "connect-src 'self' ws: wss:; " <>
          "frame-ancestors 'none';"
    }

    plug ToweropsWeb.Plugs.CaptureTimezone
    plug :fetch_current_scope_for_user
    plug ToweropsWeb.Plugs.UpdateSessionActivity
    plug :store_return_to_for_liveview
    plug ToweropsWeb.Plugs.DetectEUUser
    plug ToweropsWeb.Plugs.CheckPolicyConsent
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  pipeline :mobile_api do
    plug :accepts, ["json"]
    plug ToweropsWeb.Plugs.MobileAuth
  end

  pipeline :api_v1 do
    plug :accepts, ["json"]
    plug ToweropsWeb.Plugs.ApiAuth
  end

  # Rate limiting pipelines
  pipeline :rate_limit_auth do
    plug RateLimit, type: :auth
  end

  pipeline :rate_limit_api do
    plug RateLimit, type: :api
  end

  # Health check endpoint for Kubernetes probes (no authentication required)
  scope "/", ToweropsWeb do
    get "/health", HealthController, :index
    get "/health/time", HealthController, :time
  end

  scope "/", ToweropsWeb do
    pipe_through :browser

    get "/", PageController, :home
    get "/privacy", PageController, :privacy
    get "/terms", PageController, :terms
    get "/docs/api", ApiDocsController, :index
    live "/help", HelpLive.Index, :index
  end

  # Account API routes (requires browser authentication)
  scope "/api/v1/account", ToweropsWeb.Api do
    pipe_through [:browser, :require_authenticated_user]

    get "/data", AccountDataController, :show
  end

  # Agent communication via WebSocket channel at /socket/agent
  # See ToweropsWeb.AgentChannel for implementation

  # Mobile Auth API routes (no authentication required for login flow)
  # Rate limited to prevent brute-force attacks on QR token verification
  scope "/api/v1/mobile/auth", ToweropsWeb.Api do
    pipe_through [:api, :rate_limit_auth]

    post "/qr/verify", MobileAuthController, :verify_qr_token
    post "/qr/complete", MobileAuthController, :complete_qr_login
  end

  # Mobile API routes (requires mobile authentication)
  # Rate limited to prevent API abuse
  scope "/api/v1/mobile", ToweropsWeb.Api do
    pipe_through [:mobile_api, :rate_limit_api]

    # Auth session management
    get "/auth/session", MobileAuthController, :get_session
    delete "/auth/session", MobileAuthController, :revoke_session

    # Data endpoints
    get "/organizations", MobileController, :list_organizations
    get "/organizations/:organization_id/sites", MobileController, :list_sites
    get "/organizations/:organization_id/devices", MobileController, :list_devices
    get "/organizations/:organization_id/alerts", MobileController, :list_alerts
    get "/devices/:id", MobileController, :get_equipment
  end

  # API v1 routes (requires API token authentication)
  # Rate limited to prevent API abuse
  scope "/api/v1", V1 do
    pipe_through [:api_v1, :rate_limit_api]

    resources "/sites", SitesController, except: [:new, :edit]
    resources "/devices", DevicesController, except: [:new, :edit]
  end

  # Webhook routes (shared secret authentication)
  pipeline :webhook do
    plug :accepts, ["json"]
    plug ToweropsWeb.Plugs.WebhookAuth
  end

  scope "/api/v1/webhooks", V1 do
    pipe_through :webhook

    post "/agent-release", AgentReleaseWebhookController, :create
  end

  # Gaiia webhook routes (per-organization secret verification in controller)
  scope "/api/v1/webhooks", V1 do
    pipe_through [:api, :rate_limit_api]

    post "/gaiia/:organization_id", GaiiaWebhookController, :create
  end

  # Admin API routes (requires superuser API token)
  scope "/admin/api", V1 do
    pipe_through :api_v1

    # MIB file management
    get "/mibs", MibController, :index
    post "/mibs", MibController, :upload
    delete "/mibs/:vendor", MibController, :delete

    # GeoIP database management
    post "/geoip/import", GeoipController, :import_database
  end

  # Enable LiveDashboard in production with authentication
  scope "/admin" do
    pipe_through [:browser, :require_authenticated_user, :require_superuser]

    live_dashboard "/dashboard",
      metrics: ToweropsWeb.Telemetry,
      ecto_repos: [Towerops.Repo],
      ecto_psql_extras_options: [
        # Exclude TimescaleDB internal tables from constraint checks
        missing_fk_constraints: [
          exclude: ~r/^_(hyper_|materialized_hypertable_)/
        ]
      ]
  end

  # Enable Oban Web (superuser only)
  scope "/admin" do
    pipe_through [:browser, :require_authenticated_user, :require_superuser]

    oban_dashboard("/oban")
    get "/headers", ToweropsWeb.DebugController, :headers
  end

  # Enable Swoosh mailbox preview in development
  if Application.compile_env(:towerops, :dev_routes) do
    scope "/dev" do
      pipe_through :browser

      forward "/mailbox", Plug.Swoosh.MailboxPreview
    end
  end

  ## Authentication routes
  ## Rate limited to prevent brute-force attacks

  scope "/", ToweropsWeb do
    pipe_through [:browser, :redirect_if_user_is_authenticated, :rate_limit_auth]

    live "/users/register", UserRegistrationLive, :new
  end

  scope "/", ToweropsWeb do
    pipe_through [:browser, :require_authenticated_user]

    get "/users/settings/confirm-email/:token", UserSettingsController, :confirm_email
  end

  scope "/", ToweropsWeb do
    pipe_through [:browser, :rate_limit_auth]

    get "/users/log-in", UserSessionController, :new
    get "/users/log-in/totp", UserSessionController, :totp_verification_form
    post "/users/log-in/totp", UserSessionController, :verify_totp
    get "/users/log-in/:token", UserSessionController, :confirm
    post "/users/log-in", UserSessionController, :create
    delete "/users/log-out", UserSessionController, :delete

    get "/users/reset-password", UserResetPasswordController, :new
    post "/users/reset-password", UserResetPasswordController, :create
    live "/users/reset-password/:token", UserResetPasswordLive, :edit
  end

  # Sudo mode verification routes
  scope "/", ToweropsWeb do
    pipe_through [:browser, :require_authenticated_user]

    get "/users/sudo-verify", UserSudoController, :new
    post "/users/sudo-verify", UserSudoController, :verify
  end

  ## Admin routes (superuser only)

  scope "/", ToweropsWeb do
    pipe_through [:browser, :require_authenticated_user, :require_superuser]

    post "/admin/impersonate/:user_id", AdminController, :start_impersonate
    delete "/admin/impersonate", AdminController, :stop_impersonate
  end

  live_session :require_superuser,
    on_mount: [
      {ToweropsWeb.UserAuth, :load_cookie_consent},
      {ToweropsWeb.UserAuth, :require_authenticated_user},
      {ToweropsWeb.UserAuth, :require_totp_enrollment},
      {ToweropsWeb.UserAuth, :require_superuser},
      {ToweropsWeb.UserAuth, :handle_policy_consent}
    ] do
    scope "/admin", ToweropsWeb.Admin do
      pipe_through [:browser, :require_authenticated_user, :require_superuser]

      live "/", DashboardLive, :index
      live "/users", UserLive.Index, :index
      live "/organizations", OrgLive.Index, :index
      live "/audit", AuditLive.Index, :index
      live "/monitoring", MonitoringLive, :index
      live "/agents", AgentLive.Index, :index
      live "/security", SecurityLive.Index, :index
    end
  end

  ## Organization routes

  live_session :require_sudo_mode,
    on_mount: [
      {ToweropsWeb.UserAuth, :load_cookie_consent},
      {ToweropsWeb.UserAuth, :require_authenticated_user},
      {ToweropsWeb.UserAuth, :require_totp_enrollment},
      {ToweropsWeb.UserAuth, :require_sudo_mode},
      {ToweropsWeb.UserAuth, :handle_policy_consent}
    ] do
    scope "/", ToweropsWeb do
      pipe_through [:browser, :require_authenticated_user]

      live "/users/settings", UserSettingsLive, :index
      live "/users/my-data", AccountLive.MyData, :index
      live "/account/activity", AccountLive.Activity, :index
    end
  end

  # TOTP enrollment page - requires auth but NOT TOTP (since user is enrolling)
  live_session :totp_enrollment,
    on_mount: [
      {ToweropsWeb.UserAuth, :load_cookie_consent},
      {ToweropsWeb.UserAuth, :require_authenticated_user}
    ] do
    scope "/", ToweropsWeb do
      pipe_through [:browser, :require_authenticated_user]

      live "/account/totp-enrollment", AccountLive.TotpEnrollment, :index
    end
  end

  live_session :require_authenticated_user,
    on_mount: [
      {ToweropsWeb.UserAuth, :load_cookie_consent},
      {ToweropsWeb.UserAuth, :require_authenticated_user},
      {ToweropsWeb.UserAuth, :require_totp_enrollment},
      {ToweropsWeb.UserAuth, :handle_policy_consent}
    ] do
    scope "/", ToweropsWeb do
      pipe_through [:browser, :require_authenticated_user]

      live "/mobile/qr-login", MobileQRLive, :index
      live "/orgs", OrgLive.Index, :index
      live "/orgs/new", OrgLive.New, :new
    end
  end

  live_session :require_authenticated_user_and_organization,
    on_mount: [
      {ToweropsWeb.UserAuth, :load_cookie_consent},
      {ToweropsWeb.UserAuth, :require_authenticated_user},
      {ToweropsWeb.UserAuth, :require_totp_enrollment},
      {ToweropsWeb.UserAuth, :load_current_organization},
      {ToweropsWeb.UserAuth, :handle_policy_consent}
    ] do
    scope "/orgs/:org_slug", ToweropsWeb do
      pipe_through [:browser, :require_authenticated_user, :load_current_organization]

      live "/settings", Org.SettingsLive, :index
      live "/settings/integrations", Org.IntegrationsLive, :index
      live "/settings/integrations/preseem/devices", Org.PreseemDevicesLive, :index
      live "/settings/integrations/preseem/insights", Org.PreseemInsightsLive, :index
      live "/settings/integrations/gaiia/mapping", Org.GaiiaMappingLive, :index
      live "/settings/integrations/gaiia/reconciliation", Org.GaiiaReconciliationLive, :index
    end
  end

  live_session :require_authenticated_user_with_default_org,
    on_mount: [
      {ToweropsWeb.UserAuth, :load_cookie_consent},
      {ToweropsWeb.UserAuth, :require_authenticated_user},
      {ToweropsWeb.UserAuth, :require_totp_enrollment},
      {ToweropsWeb.UserAuth, :load_default_organization},
      {ToweropsWeb.UserAuth, :handle_policy_consent}
    ] do
    scope "/", ToweropsWeb do
      pipe_through [:browser, :require_authenticated_user]

      # Dashboard route
      live "/dashboard", DashboardLive, :index

      # Alert routes
      live "/alerts", AlertLive.Index, :index

      # Agent routes
      live "/agents", AgentLive.Index, :index
      live "/agents/:id/edit", AgentLive.Edit, :edit
      live "/agents/:id", AgentLive.Show, :show

      # Site routes
      live "/sites", SiteLive.Index, :index
      live "/sites/new", SiteLive.Form, :new
      live "/sites/:id", SiteLive.Show, :show
      live "/sites/:id/edit", SiteLive.Form, :edit

      # Device routes
      live "/devices", DeviceLive.Index, :index
      live "/devices/new", DeviceLive.Form, :new
      live "/devices/:id", DeviceLive.Show, :show
      live "/devices/:id/edit", DeviceLive.Form, :edit
      live "/devices/:id/graph/check", GraphLive.Show, :show
      live "/devices/:id/graph/:sensor_type", GraphLive.Show, :show
      live "/devices/:device_id/backups/compare", MikrotikBackupLive.Compare, :compare
      live "/devices/:device_id/config-timeline", ConfigTimelineLive, :index

      # Insights route
      live "/insights", InsightsLive.Index, :index

      # Subscriber trace
      live "/trace", TraceLive.Index, :index

      # Activity feed
      live "/activity", ActivityFeedLive, :index

      # Changelog
      live "/changelog", ChangelogLive, :index

      # Network map route
      live "/network-map", NetworkMapLive, :index
    end
  end
end
