require_dependency "safe_params"
require_dependency "paginator"

module ApplicationHelper
  def legacy_admin_url(path, query = {})
    uri = URI(Settings.twitch.rails.host).tap do |uri|
      uri.path = path
      uri.query = query.to_param
    end.to_s
  end

  def safe_params
    @safe_params ||= SafeParams.new params
  end

  def add_sidebar(text, namespace, policy_paths)
    policy_paths.map do |policy_name, path|
      next unless policy(policy_name).allowed?

      klass = "active" if current_namespace == namespace

      return {text: text, class: klass, path: path}
    end

    return nil
  end

  def add_tools_sidebar(text, namespace, policy_paths)
    policy_paths.map do |policy_name, path|
      next unless policy(policy_name).allowed?

      klass = "active" if current_namespace == "tools" && current_subnamespace == namespace

      return {text: text, class: klass, path: path}
    end

    return nil
  end

  def register_service_sidebar(sidebar)
    return unless sidebar

    @service_sidebars[sidebar[:text]] = sidebar
  end

  def register_tools_sidebar(sidebar)
    return unless sidebar

    @tools_sidebars[sidebar[:text]] = sidebar
  end

  def generate_services_sidebar
    @service_sidebars = {}

    render "layouts/services"

    content_tag :nav, class: "warp warp--light", role: "navigation" do
      content_tag :dl, class: 'warp__list warp__list--md' do
        output = content_tag :dt, class: 'warp__item warp__item--header' do
          content_tag :span, 'Services'
        end
        output += @service_sidebars.sort_by { |text, sidebar| sidebar[:text] }.map do |text, sidebar|
          content_tag :dd, class: "warp__item #{sidebar[:class]}" do
            link_to sidebar[:text], sidebar[:path]
          end
        end.join.html_safe
        output
      end
    end
  end

  def generate_tools_sidebar
    @tools_sidebars = {}

    render "layouts/tools"

    content_tag :nav, class: "warp warp--light", role: "navigation" do
      content_tag :dl, class: 'warp__list warp__list--md' do
        output = content_tag :dt, class: 'warp__item warp__item--header' do
          content_tag :span, 'Tools'
        end
        output += @tools_sidebars.sort_by { |text, sidebar| sidebar[:text] }.map do |text, sidebar|
          content_tag :dd, class: "warp__item #{sidebar[:class]}" do
            link_to sidebar[:text], sidebar[:path]
          end
        end.join.html_safe
        output
      end
    end
  end

  def generate_sidebars(*sidebars)
    sidebars.join(" ")
  end

  def render_time(time, format: "%a, %e %b %Y %H:%M:%S %z", zone: 'UTC')
    return unless time
    current_offset = Time.now.in_time_zone(zone).formatted_offset
    time.to_datetime.utc.localtime(current_offset).strftime(format)
  end

  def format_string_for_date_field(string)
    Time.parse(string).utc.strftime("%Y-%m-%d") rescue ""
  end

  def friendly_time(timestamp:)
    datetime = timestamp.to_datetime rescue nil

    return haml_tag :span, 'N/A', class: 'label label-default' unless datetime

    formatted_utc = render_time(datetime, format: "%Y-%m-%d %H:%M:%S UTC")
    formatted_pt  = render_time(datetime, format: "%Y-%m-%d %H:%M:%S %z", zone: History::TIME_ZONE)

    display_content = formatted_utc
    haml_tag(:span, data: { 'tooltip': formatted_pt.to_s, 'tooltip-position': 'right' }) do
      haml_tag(:time, display_content)
    end
  end

  def url_params
    hash = params.except(:controller, :action, :page)
    # TODO: Fix this dirty hack of normalizing ActionController::Parameters in params
    hash = JSON.parse hash.to_json
    ActiveSupport::HashWithIndifferentAccess.new hash
  end

  def paginate(objs, options = {})
    options = {
      page: params[:page],
      url_params: options[:url_params],
      context: self,
    }

    paginator = Paginator.new objs, options
    render "shared/pagination", paginator: paginator
  end

  def params_value(*args)
    args.inject(params) do |_, k|
      _[k] rescue nil
    end
  end

  def active_tab(cont)
   "tabs__item--active" if current_controller == cont
  end

  def current_namespace
    params[:controller].split("/").first
  end

  def current_subnamespace
    params[:controller].split("/").second
  end

  def current_controller
    params[:controller].split("/").last
  end

  def generate_title
    [current_namespace, current_controller, params[:action], params[:id]].compact.map(&:humanize).join(" > ")
  end

  def page_title(title)
    content_for(:title) do
      title
    end
  end

  # render an unauthorized link if the user is unauthorized to view the
  # attribute. otherwise, render the actual atribute.
  #
  # attr must be registered on the service with the `attributes` class method.
  def redact(obj, attr)
    if @user.errors.include?(attr)
      return render(
        partial: 'shared/redacted_attribute',
        locals: { errors: obj.errors[attr] }
      )
    end
    obj.send(attr)
  end

  def authorized_submit_tag(*args, **options)
    extra_options = {}
    unless policy(options[:item]).send(options[:method])
      extra_options = { disabled: true }
    end
    submit_tag(*args, **options.except(:item, :method), **extra_options)
  end

  # Check a client's session notice cookies,
  # and create alerts via Rails' `Flash` mechanism
  # `flash` is basically request level storage
  def flash_session_notifications
    return unless cookies[:session_notice].present? # nothing to do without cookies!

    # let's transform some cookies!
    notices =
      cookies
      .encrypted[:session_notice]                               # decrypt the session's notice tokens
      .map(&:to_sym)                                            # convert token strings back to symbols
      .select { |token| Notification::NOTICES.key?(token) }     # filter out unknown tokens
      .each_with_object({}) do |notice, hash|                   # start building a structure for flashing
        type = Notification::NOTICES[notice][:type] || :warning # use the notice type as the hash key
        hash[type] =
          [
            hash[type],                                         # combine any existing notice array
            [                                                   # with a new array containing this notice
              sanitize(                                         # sanitize our notice content for good measure
                Notification::NOTICES[notice][:content],
                {
                  tags: %w[strong em a br span],                # allowed tags
                  attributes: %w[href style id]                 # allowed attributes
                }
              )
            ]
          ]
          .flatten                                              # squash the resulting array nest
          .compact                                              # remove any nil or empty entries
      end

    # now we just hand them off to the flash
    notices
      .map do |type, notices|
        flash.now[type] = notices
      end
  end
end
