ActiveAdmin.register WarpEngine::ApplicationToken, as: "Application Token" do
  actions :index, :show, :new, :create, :edit, :update, :destroy
  permit_params :name, :owner_id, :expires_at, :scopes_string, :unrestricted

  menu parent: "🌀 WarpEngine", priority: 9, label: "🎟️ App Tokens"

  config.sort_order = "created_at_desc"
  config.batch_actions = false

  scope :all, default: true
  scope("Active")  { |scope| scope.where("expires_at IS NULL OR expires_at > ?", Time.current) }
  scope("Expired") { |scope| scope.where("expires_at <= ?", Time.current) }

  index do
    id_column
    column :name
    column("Token") { |t| code "#{t.token_prefix}…", style: "font-family:monospace;" }
    column("Owner") { |t| t.owner.try(:email) || t.owner.try(:name) || "#{t.owner_type} ##{t.owner_id}" }
    column("Scopes") { |t| t.scopes_string }
    column :unrestricted
    column :expires_at
    column :last_used_at
    column :created_at
    actions
  end

  filter :name_cont, label: "Name"
  filter :token_prefix_cont, label: "Token prefix"
  filter :expires_at
  filter :last_used_at

  form do |f|
    owner_class = WarpEngine.config.application_token_owner_class&.safe_constantize
    f.inputs do
      if f.object.new_record?
        if owner_class
          f.input :owner_id, as: :select, label: owner_class.name,
                  collection: owner_class.all.map { |o| [ o.try(:email) || o.try(:name) || "##{o.id}", o.id ] },
                  include_blank: false
        else
          f.template.concat(f.template.content_tag(:li,
            "application_token_owner_class is not configured — tokens cannot be created.",
            class: "flash flash_error"))
        end
      end
      f.input :name
      f.input :scopes_string, label: "Scopes (comma separated)",
              hint: %(The "update" scope is required for /build/publish, the "upload" scope for /build/upload.)
      f.input :unrestricted, hint: "Internal token: exempt from owner isolation (enforce_software_ownership)."
      f.input :expires_at, hint: "Leave empty for a token that never expires."
    end
    f.actions
  end

  action_item :rotate, only: :show do
    if WarpEngine.woodpecker_configured?
      link_to "Rotate Token", rotate_admin_application_token_path(resource),
              method: :post, data: { confirm: "This will revoke the current token, create a new one, and push it to Woodpecker. Continue?" }
    end
  end

  member_action :rotate, method: :post do
    result = WarpEngine::SecretSyncService.new.rotate(resource)
    if result[:rotated]
      session[:warp_engine_plain_token] = result[:new_token].plain_token
      redirect_to resource_path(result[:new_token]),
        notice: "Token rotated and synced to #{result.dig(:sync_result, :synced)&.size || 0} pipeline(s)"
    else
      redirect_to resource_path(resource),
        alert: "Rotation failed: #{result[:reason]}"
    end
  end

  show do
    if (plain = controller.instance_variable_get(:@plain_token))
      panel "⚠️ Token — shown only once, copy it now!" do
        pre plain, style: "font-family:monospace;font-size:14px;padding:8px;background:#fff3cd;user-select:all;"
      end
    end
    attributes_table do
      row :id
      row :name
      row("Token") { |t| code "#{t.token_prefix}… (SHA256 digest stored)" }
      row("Owner") { |t| "#{t.owner_type} ##{t.owner_id} — #{t.owner.try(:email) || t.owner.try(:name)}" }
      row("Scopes") { |t| t.scopes_string }
      row :unrestricted
      row :expires_at
      row :last_used_at
      row :created_at
      row :updated_at
    end
  end

  controller do
    # The plain token only exists right after creation; it travels via the
    # session to its one-time display (flash is unsuitable: the AA layout
    # renders every flash key as a message bar).
    def create
      create! do |success, _failure|
        success.html do
          session[:warp_engine_plain_token] = resource.plain_token

          if WarpEngine.woodpecker_configured?
            service = WarpEngine::SecretSyncService.new
            pipelines = service.pipelines_for_token(resource)
            if pipelines.any?
              result = service.provision(resource.plain_token, pipelines: pipelines)
              flash[:notice] = "Token created and synced to #{result[:synced].size} pipeline(s)."
              if result[:failed].any?
                flash[:alert] = "Failed to sync to #{result[:failed].size} pipeline(s)."
              end
            end
          end

          redirect_to resource_path(resource) and return
        end
      end
    end

    def show
      @plain_token = session.delete(:warp_engine_plain_token)
      show!
    end

    def destroy
      if WarpEngine.woodpecker_configured?
        WarpEngine::SecretSyncService.new.deprovision(resource)
      end
      resource.revoke!
      redirect_to collection_path, notice: "Token revoked and Woodpecker secrets cleaned up."
    end
  end
end
