# frozen_string_literal: true

module Admin
  class SsoProvidersController < Admin::BaseController
    before_action :set_sso_provider, only: %i[show edit update destroy toggle test_connection]

    def index
      authorize SsoProvider
      @sso_providers = policy_scope(SsoProvider).order(:name)

      # Load runtime providers (from YAML/env) that might not be in the database
      # This helps show users that legacy providers are active but not manageable via UI
      @runtime_providers = Rails.configuration.x.auth.sso_providers || []
      db_provider_names = @sso_providers.pluck(:name)
      @legacy_providers = @runtime_providers.reject { |p| db_provider_names.include?(p[:name].to_s) }
    end

    def show
      authorize @sso_provider
    end

    def new
      @sso_provider = SsoProvider.new
      authorize @sso_provider
    end

    def create
      @sso_provider = SsoProvider.new(processed_params)
      authorize @sso_provider

      # Auto-generate redirect_uri if not provided
      if @sso_provider.redirect_uri.blank? && @sso_provider.name.present?
        @sso_provider.redirect_uri = "#{request.base_url}/auth/#{@sso_provider.name}/callback"
      end

      if @sso_provider.save
        log_provider_change(:create, @sso_provider)
        clear_provider_cache
        redirect_to admin_sso_providers_path, notice: t(".success")
      else
        render :new, status: :unprocessable_entity
      end
    end

    def edit
      authorize @sso_provider
    end

    def update
      authorize @sso_provider

      # Auto-update redirect_uri if name changed
      params_hash = processed_params.to_h
      if params_hash[:name].present? && params_hash[:name] != @sso_provider.name
        params_hash[:redirect_uri] = "#{request.base_url}/auth/#{params_hash[:name]}/callback"
      end

      if @sso_provider.update(params_hash)
        log_provider_change(:update, @sso_provider)
        clear_provider_cache
        redirect_to admin_sso_providers_path, notice: t(".success")
      else
        render :edit, status: :unprocessable_entity
      end
    end

    def destroy
      authorize @sso_provider

      @sso_provider.destroy!
      log_provider_change(:destroy, @sso_provider)
      clear_provider_cache

      redirect_to admin_sso_providers_path, notice: t(".success")
    end

    def toggle
      authorize @sso_provider

      @sso_provider.update!(enabled: !@sso_provider.enabled)
      log_provider_change(:toggle, @sso_provider)
      clear_provider_cache

      notice = @sso_provider.enabled? ? t(".success_enabled") : t(".success_disabled")
      redirect_to admin_sso_providers_path, notice: notice
    end

    def test_connection
      authorize @sso_provider

      tester = SsoProviderTester.new(@sso_provider)
      result = tester.test!

      render json: {
        success: result.success?,
        message: result.message,
        details: result.details
      }
    end

    private
      def set_sso_provider
        @sso_provider = SsoProvider.find(params[:id])
      end

      def sso_provider_params
        params.require(:sso_provider).permit(
          :strategy,
          :name,
          :label,
          :icon,
          :enabled,
          :issuer,
          :client_id,
          :client_secret,
          :redirect_uri,
          :scopes,
          :prompt,
          settings: [
            :default_role, :scopes, :prompt,
            # SAML settings
            :idp_metadata_url, :idp_sso_url, :idp_slo_url,
            :idp_certificate, :idp_cert_fingerprint, :name_id_format,
            role_mapping: {}
          ]
        )
      end

      # Process params to convert role_mapping comma-separated strings to arrays
      def processed_params
        result = sso_provider_params.to_h

        if result[:settings].present? && result[:settings][:role_mapping].present?
          result[:settings][:role_mapping] = result[:settings][:role_mapping].transform_values do |v|
            # Convert comma-separated string to array, removing empty values
            v.to_s.split(",").map(&:strip).reject(&:blank?)
          end

          # Remove empty role mappings
          result[:settings][:role_mapping] = result[:settings][:role_mapping].reject { |_, v| v.empty? }
          result[:settings].delete(:role_mapping) if result[:settings][:role_mapping].empty?
        end

        result
      end

      def log_provider_change(action, provider)
        Rails.logger.info(
          "[Admin::SsoProviders] #{action.to_s.upcase} - " \
          "user_id=#{Current.user.id} " \
          "provider_id=#{provider.id} " \
          "provider_name=#{provider.name} " \
          "strategy=#{provider.strategy} " \
          "enabled=#{provider.enabled}"
        )
      end

      def clear_provider_cache
        ProviderLoader.clear_cache
        Rails.logger.info("[Admin::SsoProviders] Provider cache cleared by user_id=#{Current.user.id}")
      end
  end
end
