# frozen_string_literal: true

module Queries
  # Base query class to be inherited by all queries
  class BaseQuery < GraphQL::Schema::Resolver
    include SharedGraphqlMethods
    include ServiceResponse
    include Paginatable

    # Class method to define return type
    def self.return_type(return_type)
      # Create a unique name for the response type
      response_type_name = "#{name.gsub('::', '')}Response"

      # First, create the options type for pagination
      options_type_name = "#{response_type_name}Options"
      options_type = Class.new(Types::BaseObject) do
        graphql_name options_type_name
        field :total_pages, Integer, null: false
        field :total_count, Integer, null: false
        field :current_page, Integer, null: false
        field :per_page, Integer, null: false
        field :prev_page, Integer, null: true
        field :next_page, Integer, null: true
      end
      Types.const_set(options_type_name, options_type)

      # Define the response type class in Types module
      response_type = Class.new(Types::BaseObject) do
        graphql_name response_type_name
        field :data, return_type, null: true
        field :errors, [String], null: true
        field :message, String, null: false
        field :http_status, Integer, null: false
        field :options, options_type, null: true
      end

      # Register the new type
      Types.const_set(response_type_name, response_type)

      # Set the type to our new response type
      type response_type, null: false
    end

    # Class method to set permission requirements
    def self.require_permission(level = :admin_or_platform_admin)
      @permission_level = level
    end

    # Get the current user from the context
    def current_user
      context[:current_user]
    end

    # Get the current user's company
    def company
      current_user.company
    end

    # Class method to get permission requirements
    def self.permission_level
      @permission_level || :admin_or_platform_admin # Default to :admin_or_platform_admin
    end

    # Resolve method used by child mutations
    def resolve(**args)
      # Placeholder for actual resolve logic (to be overridden by subclasses)
      raise NotImplementedError, 'Subclasses must implement a resolve method'
    end

    def show_record(model_class, id)
      # Run all the before actions
      run_before_actions({ id: id }).tap do |result|
        return result if result
      end

      record = model_class.find_by(id: id)

      if record.nil?
        return failure_response(errors: ["#{model_class.name} not found"])
      end

      success_response(data: record)
    end

    def list_records(model_class, options = {})
      # Run all the before actions
      run_before_actions(options).tap { |result| return result if result }

      # Set default options while allowing overrides
      filters = options.fetch(:filters, {})
      order_by = options.fetch(:order_by, :position)
      order_direction = options.fetch(:order_direction, :asc)
      skip_company_filter = options.fetch(:skip_company_filter, false)

      # Convert page and per_page to integers, default to 1 and 10 respectively
      page = options.fetch(:page, 1).to_i
      per_page = options.fetch(:per_page, 10).to_i

      # Ensure filters is a hash
      filters = filters.to_h

      # Add company_id filter unless explicitly skipped or the model is Company
      unless skip_company_filter || model_class == Company
        filters = filters.merge(company_id: company.id.to_s)
      end

      # Apply filtering based on the passed filters hash
      query = model_class.where(filters)

      # Apply ordering based on the order_direction (asc or desc)
      query = query.order_by(order_by => order_direction)

      # Paginate the query and include total count
      paginate(query, page: page, per_page: per_page)
    end

    private

    # Override success_response to match the GraphQL type structure
    def success_response(data: nil, message: 'Success', options: nil)
      {
        data: data,
        errors: nil,
        message: message,
        http_status: 200,
        options: options
      }
    end

    # Override failure_response to match the GraphQL type structure
    def failure_response(errors: [], message: 'Error', http_status: 400)
      {
        data: nil,
        errors: Array(errors),
        message: message,
        http_status: http_status
      }
    end
  end
end 