module Symphonia
  # General controller for CRUD operations of Entity
  #
  # How to use:
  # include Symphonia::BaseController
  # def model
  #   YourModel
  # end
  # OR
  # self.model = YourModel
  #
  # def safe_attributes
  #   %i[]
  # end
  #
  # def swagger_path
  #  false # => for disable swagger
  #   "/my-custom-path" # => for custom route
  # end
  module BaseController
    extend ActiveSupport::Concern

    included do
      # before_action :authorize
      before_action :find_entity, only: [:show, :edit, :update, :destroy]

      include Rails::Pagination
      helper Symphonia::BootstrapModalHelper
      helper Symphonia::RendererHelper

      # @param [Class] model
      class_attribute :model

    end

    class_methods do

      # def model=(klass)
      #   @model = klass
      # end
      #
      # def model
      #   @model
      # end
    end

    # def model
    #   self.class.model
    # end
    # @abstract model
    # by default it guess from class name of controller
    # def model
    #   @model ||= self.class.name.remove("Controller").classify.constantize
    # end

    def index
      @query ||= model.query.new
      @query.from_params params
      @entities = @query.entities
      respond_to do |format|
        format.html do
          @entities = paginate(@entities)
          render layout: !request.xhr?
        end
        format.json do
          paginate(json: @entities)
        end
      end
    end

    def show
      respond_to do |format|
        format.html { @entity = Symphonia::EntityDecorator.new(@entity, view_context) }
        format.json { render json: @entity }
      end
    end

    def new
      @entity ||= instance_variable_set(:"@#{model_name}", model.new(params.fetch(model_name, {}).permit(safe_attributes)))
    end

    def edit
    end

    def create
      @entity ||= instance_variable_set(:"@#{model_name}", model.new(entity_params))
      respond_to do |format|
        if @entity.save
          after_create
          format.html { redirect_back_or_default @entity, notice: t(:text_created) }
          format.json { render json: @entity, status: :created, location: @entity }
        else
          format.html { render action: 'new' }
          format.json { render status: :unprocessable_entity, json: { errors: @entity.errors } }
        end
      end
    end

    def update
      respond_to do |format|
        if @entity.update(entity_params)
          after_update
          format.html { redirect_back_or_default @entity, notice: t(:text_updated) }
          format.json { head :no_content }
        else
          format.html { render action: 'edit' }
          format.json { render status: :unprocessable_entity, json: { errors: @entity.errors } }
        end
      end
    end

    def destroy
      @entity.destroy
      respond_to do |format|
        format.html { redirect_back_or_default(polymorphic_path(model), notice: t(:text_destroyed)) }
        format.json { head :no_content }
        format.js { render js: "Symphonia.filters.removeRow('#{view_context.dom_id(@entity)}')" }
      end
    end

    def model_name
      model.name.demodulize.underscore.to_sym
    end

    private

    # Use callbacks to share common setup or constraints between actions.
    def find_entity
      @entity ||= instance_variable_set(:"@#{model_name}", model.find(params[:id]))
    end

    def safe_attributes
      []
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def entity_params
      params.require(model_name).permit(safe_attributes)
    end

    def after_create

    end

    def after_update

    end

  end
end