# frozen_string_literal: true

module RedmineUxToolkit
  module Patches
    module IssueChecklistCloseGuardPatch
      def self.prepended(base)
        base.validate :ux_toolkit_prevent_closing_with_open_checklist_items
        base.validate :ux_toolkit_prevent_closing_with_open_subtasks
      end

      private

      def ux_toolkit_prevent_closing_with_open_checklist_items
        return unless RedmineUxToolkit::Services::Checklists.prevent_closing_with_open_items_enabled?
        return unless persisted?
        return unless ux_toolkit_closing_from_open_to_closed?

        open_count = RedmineUxToolkit::Services::Checklists.open_item_count_for(self)
        return if open_count.zero?

        errors.add(
          :base,
          I18n.t(:error_ux_toolkit_issue_close_blocked_by_open_checklist_items, count: open_count)
        )
      end

      def ux_toolkit_prevent_closing_with_open_subtasks
        return unless RedmineUxToolkit::Services::IssueCloseGuards.prevent_closing_with_open_subtasks_enabled?
        return unless persisted?
        return unless ux_toolkit_closing_from_open_to_closed?

        open_count = RedmineUxToolkit::Services::IssueCloseGuards.open_subtask_count_for(self)
        return if open_count.zero?

        errors.add(
          :base,
          I18n.t(:error_ux_toolkit_issue_close_blocked_by_open_subtasks, count: open_count)
        )
      end

      def ux_toolkit_closing_from_open_to_closed?
        return false unless ux_toolkit_status_id_will_change?

        new_status = IssueStatus.find_by(id: status_id)
        return false unless RedmineUxToolkit::Compatibility.issue_closed?(new_status)

        previous_status = IssueStatus.find_by(id: ux_toolkit_previous_status_id)
        !RedmineUxToolkit::Compatibility.issue_closed?(previous_status)
      end

      def ux_toolkit_status_id_will_change?
        # Redmine 6.1 uses Rails dirty tracking; fallbacks keep the patch tolerant across minor updates.
        if respond_to?(:will_save_change_to_status_id?)
          will_save_change_to_status_id?
        elsif respond_to?(:status_id_changed?)
          status_id_changed?
        else
          status_id != ux_toolkit_previous_status_id
        end
      end

      def ux_toolkit_previous_status_id
        if respond_to?(:status_id_in_database)
          status_id_in_database
        elsif respond_to?(:status_id_was)
          status_id_was
        end
      end
    end
  end
end
