# frozen_string_literal: true

class UxToolkitRecurringIssueRulesController < ApplicationController
  before_action :require_login
  before_action :require_recurring_issue_rule_management
  before_action :find_rule, only: [:edit, :update, :destroy]
  before_action :load_form_options, only: [:new, :create, :edit, :update]

  helper :issues
  helper :projects

  def index
    @rules = UxToolkitRecurringIssueRule
             .manageable_by(User.current)
             .includes(:project, :tracker, :priority, :assigned_to, :category)
             .ordered
  end

  def new
    @rule = UxToolkitRecurringIssueRule.new(
      enabled: true,
      interval: UxToolkitRecurringIssueRule::INTERVAL_WEEKLY,
      next_run_on: Date.current,
      priority: IssuePriority.default || IssuePriority.active.first
    )
  end

  def create
    @rule = UxToolkitRecurringIssueRule.new(rule_params)
    @rule.created_by = User.current
    @rule.updated_by = User.current

    unless project_manageable?(@rule.project)
      render_403
      return
    end

    if @rule.save
      flash[:notice] = l(:notice_ux_toolkit_recurring_issue_rule_created)
      redirect_to ux_toolkit_recurring_issue_rules_path
    else
      flash.now[:error] = rule_error(@rule, :error_ux_toolkit_recurring_issue_rule_create_failed)
      render :new, status: :unprocessable_entity
    end
  end

  def edit; end

  def update
    @rule.assign_attributes(rule_params)
    @rule.updated_by = User.current

    unless project_manageable?(@rule.project)
      render_403
      return
    end

    if @rule.save
      flash[:notice] = l(:notice_ux_toolkit_recurring_issue_rule_updated)
      redirect_to ux_toolkit_recurring_issue_rules_path
    else
      flash.now[:error] = rule_error(@rule, :error_ux_toolkit_recurring_issue_rule_update_failed)
      render :edit, status: :unprocessable_entity
    end
  end

  def destroy
    if @rule.destroy
      flash[:notice] = l(:notice_ux_toolkit_recurring_issue_rule_deleted)
    else
      flash[:error] = l(:error_ux_toolkit_recurring_issue_rule_delete_failed)
    end

    redirect_to ux_toolkit_recurring_issue_rules_path
  end

  private

  def require_recurring_issue_rule_management
    return true if User.current.admin?
    return true if manageable_projects.any?

    render_403
    false
  end

  def find_rule
    @rule = UxToolkitRecurringIssueRule.manageable_by(User.current).find(params[:id])
  rescue ActiveRecord::RecordNotFound
    render_404
  end

  def load_form_options
    @projects = manageable_projects
    @trackers = Tracker.sorted.to_a
    @priorities = IssuePriority.active.to_a
    project = selected_project
    tracker = selected_tracker
    @assignable_users = project ? project.assignable_users(tracker).to_a : []
    @categories = project ? project.issue_categories.to_a : []
  end

  def selected_project
    project_id = rule_params_for_options[:project_id].presence || @rule&.project_id
    project_id.present? ? Project.find_by(id: project_id) : @projects.first
  end

  def selected_tracker
    tracker_id = rule_params_for_options[:tracker_id].presence || @rule&.tracker_id
    tracker_id.present? ? Tracker.find_by(id: tracker_id) : nil
  end

  def manageable_projects
    @manageable_projects ||= begin
      scope = User.current.admin? ? Project.active : Project.visible(User.current).active
      scope.to_a.select {|project| project_manageable?(project)}
    end
  end

  def project_manageable?(project)
    return false unless project
    return true if User.current.admin?

    User.current.allowed_to?(:manage_ux_toolkit_recurring_issues, project)
  end

  def rule_params
    params.require(:ux_toolkit_recurring_issue_rule).permit(
      :enabled,
      :project_id,
      :tracker_id,
      :subject,
      :description,
      :priority_id,
      :assigned_to_id,
      :category_id,
      :interval,
      :next_run_on
    )
  end

  def rule_params_for_options
    params.fetch(:ux_toolkit_recurring_issue_rule, {}).permit(:project_id, :tracker_id)
  end

  def rule_error(rule, fallback_key)
    rule.errors.full_messages.to_sentence.presence || l(fallback_key)
  end
end
