module Comee
  module Core
    module Common
      extend ActiveSupport::Concern
      include Pagination

      included do
        before_action :set_clazz
        before_action :set_object, only: %i[show update]
      end

      def index
        data = nil
        options = {}
        if block_given?
          incoming = yield
          if incoming.instance_of?(Array)
            data, options = incoming
          elsif incoming.instance_of?(Hash)
            options = incoming
          else
            data = incoming
          end
        else
          data = @clazz.all
        end
        total = data.count
        data = data.then(&paginate) if params[:page]
        result = {
          success: true,
          data: options.key?(:fields) ? serialize(data, include: options[:fields]) : serialize(data)
        }
        if params[:page]
          result[:page] = params[:page]
          result[:total] = total
        end

        render json: result
      end

      def show
        data = nil
        options = {}
        if block_given?
          incoming = yield
          if incoming.instance_of?(Array)
            data, options = incoming
          elsif incoming.instance_of?(Hash)
            options = incoming
          else
            data = incoming
          end
        else
          data = @obj
        end
        result = {
          success: true,
          data: options.key?(:fields) ? serialize(data, include: options[:fields]) : serialize(data)
        }
        render json: result
      end

      def create
        obj = if block_given?
                yield
              else
                @clazz.new(model_params)
              end
        if obj.save
          render json: {success: true, data: serialize(obj)}, status: :created
        else
          render json: {success: false, error: obj.errors.full_messages[0]}, status: :unprocessable_entity
        end
      rescue StandardError => e
        render json: {success: false, error: e.message}
      end

      def update
        obj = if block_given?
                yield
              else
                obj = @obj
              end
        if obj.update(model_params)
          render json: {success: true, data: serialize(obj)}
        else
          render json: {success: false, error: obj.errors.full_messages[0]}, status: :unprocessable_entity
        end
      rescue StandardError => e
        render json: {success: false, error: e.message}
      end

      private

      def serialize(data, options = {})
        ActiveModelSerializers::SerializableResource.new(data, options)
      end

      def set_clazz
        @clazz = "Comee::Core::#{controller_name.classify}".constantize
      end

      def set_object
        @obj = @clazz.find(params[:id])
      end

      # This class should be overridden by respective child controllers
      def model_params; end
    end
  end
end