# frozen_string_literal: true

# This is the main Alchemy controller all other controllers inherit from.
#
module Alchemy
  class BaseController < ApplicationController
    include Alchemy::ConfigurationMethods
    include Alchemy::AbilityHelper
    include Alchemy::ControllerActions
    include Alchemy::Modules

    protect_from_forgery

    before_action :mailer_set_url_options
    before_action :set_locale

    helper "alchemy/admin/form"

    rescue_from CanCan::AccessDenied do |exception|
      permission_denied(exception)
    end

    private

    # Sets +I18n.locale+ to current Alchemy language.
    #
    def set_locale
      return unless Current.language

      ::I18n.locale = Current.language&.locale
    end

    def not_found_error!(msg = "Not found \"#{request.fullpath}\"")
      raise ActionController::RoutingError, msg
    end

    # Store current request path into session,
    # so we can later redirect to it.
    def store_location
      session[:redirect_path] = request.path
    end

    def mailer_set_url_options
      ActionMailer::Base.default_url_options[:host] = request.host_with_port
    end

    protected

    def permission_denied(exception = nil)
      if exception
        Rails.logger.debug <<-WARN.strip_heredoc
          /!\\ Failed to permit #{exception.action} on #{exception.subject.inspect} for:
          #{current_alchemy_user.inspect}
        WARN
      end
      if request.format.json?
        render json: {message: Alchemy.t("You are not authorized")}, status: :unauthorized
      elsif current_alchemy_user
        handle_redirect_for_user
      else
        handle_redirect_for_guest
      end
    end

    def handle_redirect_for_user
      flash[:warning] = Alchemy.t("You are not authorized")
      if can?(:index, :alchemy_admin_dashboard)
        redirect_or_render_notice
      else
        redirect_to Alchemy.unauthorized_path
      end
    end

    def redirect_or_render_notice
      if request.xhr?
        respond_to do |format|
          format.js do
            render plain: flash.discard(:warning), status: 403
          end
          format.html do
            render partial: "alchemy/admin/partials/flash",
              locals: {message: flash[:warning], flash_type: "warning"}
          end
        end
      elsif turbo_frame_request?
        render "403", status: 403
      else
        redirect_to(alchemy.admin_dashboard_path)
      end
    end

    def handle_redirect_for_guest
      flash[:info] = Alchemy.t("Please log in")
      if request.xhr?
        render :permission_denied
      else
        store_location
        redirect_to Alchemy.login_path
      end
    end

    # Logs the current exception to the error log.
    def exception_logger(error)
      Rails.logger.error("\n#{error.class} #{error.message} in #{error.backtrace.first}")
      Rails.logger.error(error.backtrace[1..50].each { |line|
        line.gsub(/#{Rails.root}/, "")
      }.join("\n"))
    end
  end
end
