# frozen_string_literal: true

module RedmineUxToolkit
  module Patches
    module SettingsControllerPatch
      def plugin
        normalize_ux_toolkit_settings_tab if params[:id].to_s == 'redmine_ux_toolkit'

        if request.post? && params[:id].to_s == 'redmine_ux_toolkit'
          sanitize_stale_issue_days
          sanitize_issue_reminder_settings
          sanitize_helpdesk_mail_fetch_settings
          sanitize_cron_monitoring_settings
          sanitize_issue_quality_settings
          sanitize_sla_light_settings
          sanitize_repository_refresh_settings
          sanitize_attachment_storage_settings
          save_custom_css
          save_tracker_notices
          save_tracker_ticket_templates
          save_repository_refresh_states
        end

        super
      end

      private

      def normalize_ux_toolkit_settings_tab
        params[:tab] = 'landing_pages_and_links' if params[:tab].to_s == 'modern_ui'
      end

      def sanitize_stale_issue_days
        return unless params[:settings].respond_to?(:key?)
        return unless params[:settings].key?(:stale_issue_days) || params[:settings].key?('stale_issue_days')

        key = params[:settings].key?(:stale_issue_days) ? :stale_issue_days : 'stale_issue_days'
        value = params[:settings][key].to_i
        value = 14 unless (1..365).cover?(value)
        params[:settings][key] = value.to_s
      end

      def sanitize_issue_reminder_settings
        return unless params[:settings].respond_to?(:key?)

        sanitize_issue_reminder_days_before_due
        sanitize_issue_reminder_send_time
        sanitize_issue_reminder_time_zone
        sanitize_issue_reminder_weekdays
      end

      def sanitize_issue_quality_settings
        return unless params[:settings].respond_to?(:key?)

        sanitize_issue_quality_minimum(:issue_quality_min_subject_length, 8)
        sanitize_issue_quality_minimum(:issue_quality_min_description_length, 30)
      end

      def sanitize_sla_light_settings
        return unless params[:settings].respond_to?(:key?)

        sanitize_positive_integer(:sla_light_first_response_hours, 8)
        sanitize_positive_integer(:sla_light_resolution_hours, 72)
        sanitize_sla_light_pause_status_ids
      end

      def sanitize_repository_refresh_settings
        return unless params[:settings].respond_to?(:key?)

        sanitize_repository_refresh_interval
        sanitize_repository_refresh_limit
        sanitize_repository_refresh_runtime
      end

      def sanitize_attachment_storage_settings
        return unless params[:settings].respond_to?(:key?)

        sanitize_attachment_storage_retention
        sanitize_attachment_storage_cleanup_limit
      end

      def sanitize_issue_reminder_days_before_due
        key = settings_key(:issue_reminder_days_before_due)
        return unless key

        value = params[:settings][key].to_i
        params[:settings][key] = (value.positive? ? value : 7).to_s
      end

      def sanitize_issue_reminder_send_time
        key = settings_key(:issue_reminder_send_time)
        return unless key

        value = params[:settings][key].to_s
        params[:settings][key] = value.match?(/\A(?:[01]\d|2[0-3]):[0-5]\d\z/) ? value : '08:00'
      end

      def sanitize_helpdesk_mail_fetch_settings
        return unless params[:settings].respond_to?(:key?)

        key = settings_key(:helpdesk_mail_fetch_interval_minutes)
        return unless key

        value = params[:settings][key].to_i
        allowed = RedmineUxToolkit::Services::HelpdeskMailFetch::ALLOWED_INTERVAL_MINUTES
        params[:settings][key] = (allowed.include?(value) ? value : 60).to_s
      end

      def sanitize_cron_monitoring_settings
        return unless params[:settings].respond_to?(:key?)

        interval_key = settings_key(:cron_monitoring_interval)
        if interval_key
          value = params[:settings][interval_key].to_s
          allowed = RedmineUxToolkit::Services::CronMonitor::ALLOWED_INTERVALS
          params[:settings][interval_key] = allowed.include?(value) ? value : 'none'
        end

        email_key = settings_key(:cron_monitoring_email)
        params[:settings][email_key] = params[:settings][email_key].to_s.strip if email_key
      end

      def sanitize_issue_reminder_time_zone
        key = settings_key(:issue_reminder_time_zone)
        return unless key

        value = params[:settings][key].to_s
        params[:settings][key] = ActiveSupport::TimeZone[value].present? ? value : ''
      end

      def sanitize_issue_reminder_weekdays
        key = settings_key(:issue_reminder_weekdays)
        return unless key

        params[:settings][key] = Array(params[:settings][key]).map(&:to_s) &
                                 RedmineUxToolkit::Services::IssueReminderEmails::WEEKDAY_KEYS
      end

      def sanitize_issue_quality_minimum(name, fallback)
        key = settings_key(name)
        return unless key

        value = params[:settings][key].to_i
        params[:settings][key] = (1..1000).cover?(value) ? value.to_s : fallback.to_s
      end

      def sanitize_positive_integer(name, fallback)
        key = settings_key(name)
        return unless key

        value = params[:settings][key].to_i
        params[:settings][key] = (1..10_000).cover?(value) ? value.to_s : fallback.to_s
      end

      def sanitize_sla_light_pause_status_ids
        key = settings_key(:sla_light_pause_status_ids)
        return unless key

        valid_ids = IssueStatus.pluck(:id).map(&:to_s)
        params[:settings][key] = Array(params[:settings][key]).map(&:to_s) & valid_ids
      end

      def sanitize_repository_refresh_interval
        key = settings_key(:repository_refresh_default_interval_minutes)
        return unless key

        value = params[:settings][key].to_i
        params[:settings][key] = RedmineUxToolkit::Services::RepositoryRefresh.allowed_interval?(value) ? value.to_s : '60'
      end

      def sanitize_repository_refresh_limit
        key = settings_key(:repository_refresh_max_per_run)
        return unless key

        value = params[:settings][key].to_i
        params[:settings][key] = (1..10).cover?(value) ? value.to_s : '1'
      end

      def sanitize_repository_refresh_runtime
        key = settings_key(:repository_refresh_max_runtime_seconds)
        return unless key

        value = params[:settings][key].to_i
        params[:settings][key] = (30..3600).cover?(value) ? value.to_s : '300'
      end

      def sanitize_attachment_storage_retention
        key = settings_key(:attachment_trash_retention_days)
        return unless key

        value = params[:settings][key].to_i
        params[:settings][key] = (1..3650).cover?(value) ? value.to_s : '30'
      end

      def sanitize_attachment_storage_cleanup_limit
        key = settings_key(:attachment_trash_cleanup_limit)
        return unless key

        value = params[:settings][key].to_i
        params[:settings][key] = (1..500).cover?(value) ? value.to_s : '50'
      end

      def settings_key(name)
        return name if params[:settings].key?(name)

        string_key = name.to_s
        params[:settings].key?(string_key) ? string_key : nil
      end

      # Redmine plugin settings save only the Setting hash by default. Tracker
      # notices use plugin-owned persistence, so the plugin persists them here.
      def save_tracker_notices
        return unless params.key?(:ux_toolkit_tracker_notices)

        notice_params = params[:ux_toolkit_tracker_notices]&.permit!
        UxToolkitTrackerNotice.save_all_from_params(notice_params&.to_h)
      end

      def save_tracker_ticket_templates
        return unless params.key?(:ux_toolkit_tracker_ticket_templates)

        default_params = params[:ux_toolkit_tracker_ticket_templates]&.permit!
        UxToolkitTrackerTicketTemplate.save_global_defaults_from_params(default_params&.to_h)
      rescue ActiveRecord::RecordInvalid
        flash[:error] = l(:error_ux_toolkit_tracker_ticket_template_defaults_save_failed)
      end

      def save_repository_refresh_states
        return unless params.key?(:ux_toolkit_repository_refresh_states)

        refresh_params = params[:ux_toolkit_repository_refresh_states]&.permit!
        UxToolkitRepositoryRefreshState.save_all_from_params(refresh_params&.to_h)
      rescue ActiveRecord::RecordInvalid
        flash[:error] = l(:error_ux_toolkit_repository_refresh_settings_save_failed)
      end

      def save_custom_css
        return unless params.key?(:ux_toolkit_custom_css)

        custom_code_params = params[:ux_toolkit_custom_css]&.permit(:css, :javascript)
        custom_code = custom_code_params&.to_h || {}
        RedmineUxToolkit::Services::CustomCss.update(
          css: custom_code.fetch('css', ''),
          javascript: custom_code.fetch('javascript', '')
        )
      end
    end
  end
end
