require 'net/http'

module Cas
  module Client
    class Middleware
      def initialize(app, &block)
        @app = app

        Cas::Client.configure(&block) if block_given?
      end

      def call(env)
        @request = Rack::Request.new(env)
        status, headers, rack_body = @app.call(env)

        if ticket_validation?
          attributes = server.validate_service(self_url, ticket_param)
          set_session(attributes)

          return redirect_to(self_url)
        elsif status == 401
          log(env, "Cas::Client::Middleware detected 401, Status: #{status}, Headers: #{headers}\n")

          return redirect_to(server.login_url({ service_url: self_url }))
        else
          return [status, headers, rack_body]
        end
      end

      private

      def server
        @_server ||= Cas::Client::Server.new
      end

      def set_session(attributes)
        @request.session['cas'] = attributes
      end

      def redirect_to(url, status=302)
        [ status, { 'Location' => url, 'Content-Type' => 'text/plain' }, ["Redirecting you to #{url}"] ]
      end

      def self_url
        @request.url.split('?')[0]
      end

      def ticket_validation?
        @request.get? && param_service_ticket?
      end

      def ticket_param
        @request.params['ticket']
      end

      def param_service_ticket?
        ticket_param.to_s =~ /\AST\-[^\s]{1,253}\Z/
      end

      def log(env, message, level = :info)
        if env['rack.logger']
          env['rack.logger'].send(level, message)
        else
          env['rack.errors'].write(message)
        end
      end
    end
  end
end