module JSONAPI::ControllerHelpers::Parsing

def invalid_sort_fields_for_columns(sorts, available_columns)

def invalid_sort_fields_for_columns(sorts, available_columns)
  sorts.filter_map do |sort_field|
    field = JSONAPI::RelationshipHelpers.extract_sort_field_name(sort_field)
    field unless available_columns.include?(field.to_s)
  end
end

def jsonapi_attributes

def jsonapi_attributes
  (jsonapi_params[:attributes] || {}).to_h
end

def jsonapi_content_type?

def jsonapi_content_type?
  request.content_type&.include?("application/vnd.api+json")
end

def jsonapi_id

def jsonapi_id
  data = jsonapi_params
  return data.first[:id].to_s.presence if data.is_a?(Array)
  data[:id].to_s.presence
end

def jsonapi_params

def jsonapi_params
  data = params.require(:data)
  return data if data.is_a?(Array)
  permitted = data.permit(:type, :id, attributes: {})
  permitted[:relationships] = permit_relationships(data) if data[:relationships].present?
  permitted
end

def jsonapi_relationships

def jsonapi_relationships
  jsonapi_params[:relationships] || {}
end

def jsonapi_type

def jsonapi_type
  data = jsonapi_params
  return data.first[:type] if data.is_a?(Array)
  data[:type]
end

def modifying_request?

def modifying_request?
  request.post? || request.patch? || request.put? || request.delete?
end

def parse_and_apply_json_body

def parse_and_apply_json_body
  body = request.body.read
  request.body.rewind
  return if body.blank?
  parsed = JSON.parse(body)
  parsed.deep_transform_keys!(&:to_sym)
  request.env["action_dispatch.request.request_parameters"] = parsed
end

def parse_fields_param

def parse_fields_param
  return {} unless params[:fields]
  params[:fields].permit!.to_h.each_with_object({}) do |(type, fields), hash|
    hash[type.to_sym] = fields.to_s.split(",").map(&:strip)
  end
end

def parse_filter_param

def parse_filter_param
  return {} unless params[:filter]
  raw_filters = params[:filter].permit!.to_h
  JSONAPI::ParamHelpers.flatten_filter_hash(raw_filters)
end

def parse_include_param

def parse_include_param
  return [] unless params[:include]
  params[:include].to_s.split(",").map(&:strip)
end

def parse_jsonapi_body

def parse_jsonapi_body
  return unless jsonapi_content_type?
  return if params[:data].present?
  parse_and_apply_json_body
rescue JSON::ParserError
  # Invalid JSON - will be handled by validation
end

def parse_page_param

def parse_page_param
  return {} unless params[:page]
  params[:page].permit(:number, :size).to_h
end

def parse_sort_param

def parse_sort_param
  return [] unless params[:sort]
  params[:sort].to_s.split(",").map(&:strip)
end

def permit_relationships(data)

def permit_relationships(data)
  result = {}
  data[:relationships].each do |key, value|
    result[key] = value.permit(data: %i[type id]) if value.is_a?(ActionController::Parameters)
  end
  result
end

def valid_sort_fields_for_resource(resource_class, model_class)

def valid_sort_fields_for_resource(resource_class, model_class)
  model_columns = model_class.column_names.map(&:to_sym)
  resource_sortable_fields = resource_class.permitted_sortable_fields.map(&:to_sym)
  (model_columns + resource_sortable_fields).uniq.map(&:to_s)
end