module Twitch
  class ReservationsController < Twitch::BaseController
    before_action :set_reservation, only: [:show, :update, :destroy]

    AUDIT_ACTION_UPDATE = "update_reservation"
    AUDIT_ACTION_CREATE = "create_reservation"
    AUDIT_ACTION_DELETE = "delete_reservation"
    AUDIT_LDAP_USER = "ldap_user"
    AUDIT_RESERVED_LOGIN = "reserved_login"

    ATTRIBUTE_TYPE = "type"
    ATTRIBUTE_REASON = "reason"
    ATTRIBUTE_LOGIN = "login"
    ATTRIBUTE_EXPIRES_ON = "expires_on"

    def index
      authorize Reservation

      if params[:find_by_login]
        reservation = Twitch::Reservation.find(params[:find_by_login])
        if !reservation.blank? && reservation.errors.empty?
          @reservation = reservation
        else
          flash.now[:error] = "Reservation with Login '#{params[:find_by_login]}' not found"
        end
      end
    end

    def update
      args = params[:twitch_reservation]
      if args.blank?
        flash[:error] = "Reservation could not be updated."
      end
      args[:login] = @reservation.login
      response = @reservation.update(args)
      if response.status == 200 || response.status == 204
        audit_update(args, current_user.ldap_login)
        flash[:success] = "Successfully modified #{@reservation.login}"
      else
        flash[:error] = "#{response.body['message']}. Reservation could not be updated."
      end
      redirect_to twitch_reservation_path(@reservation.login)
    end

    def new
      authorize Reservation
      @reservation = Twitch::Reservation.new
    end

    def create
      authorize Reservation

      args = params[:twitch_reservation]
      if args.blank?
        flash[:error] = "Reservation could not be created."
      end

      response = Twitch::Reservation.create(args)
      if response.status == 200 || response.status == 204
        audit_create(args, current_user.ldap_login)
        flash[:success] = "Successfully created #{args[:login]}"
      else
        flash[:error] = "#{response.body['message']}. Reservation could not be created."
      end
      redirect_to twitch_reservations_path
    end

    def show
    end

    def destroy
      if @reservation.destroy
        audit_delete(params[:id], current_user.ldap_login)
        flash[:success] = "Successfully removed reservation with login '#{params[:id]}'"
      else
        flash[:error] = @reservation.errors.full_messages.to_sentence
      end

      redirect_to twitch_reservations_path
    end

    private

    def audit_create(options, ldap_login)
      changes = []
      changes.push(History::ChangeSet.new(
          attribute: ATTRIBUTE_LOGIN,
          new_value: options[:login]
      ))

      changes.push(History::ChangeSet.new(
          attribute: ATTRIBUTE_TYPE,
          new_value: options[:type]
      ))

      changes.push(History::ChangeSet.new(
          attribute: ATTRIBUTE_REASON,
          new_value: options[:reason]
      ))

      changes.push(History::ChangeSet.new(
            attribute: ATTRIBUTE_EXPIRES_ON,
            new_value: options[:expires_on]
      ))

      audit = History::Audit.new(
          action: AUDIT_ACTION_CREATE,
          user_type: AUDIT_LDAP_USER,
          user_id: ldap_login,
          resource_type: AUDIT_RESERVED_LOGIN,
          resource_id: options[:login],
          changes: changes
      )

      History::AddAudit.add(audit)
    end

    def audit_update(options, ldap_login)
      changes = []
      if @reservation.type != options[:type]
        change = History::ChangeSet.new(
            attribute: ATTRIBUTE_TYPE,
            old_value: @reservation.type,
            new_value: options[:type]
        )
        changes.push(change)
      end

      if @reservation.reason != options[:reason]
        change = History::ChangeSet.new(
            attribute: ATTRIBUTE_REASON,
            old_value: @reservation.reason,
            new_value: options[:reason]
        )
        changes.push(change)
      end

      if @reservation.expires_on != options[:expires_on]
        change = History::ChangeSet.new(
            attribute: ATTRIBUTE_EXPIRES_ON,
            old_value: @reservation.expires_on,
            new_value: options[:expires_on]
        )
        changes.push(change)
      end

      return if changes.length.zero?

      audit = History::Audit.new(
          action: AUDIT_ACTION_UPDATE,
          user_type: AUDIT_LDAP_USER,
          user_id: ldap_login,
          resource_type: AUDIT_RESERVED_LOGIN,
          resource_id: options[:login],
          changes: changes
      )

      History::AddAudit.add(audit)
    end

    def audit_delete(login, ldap_login)
      audit = History::Audit.new(
          action: AUDIT_ACTION_DELETE,
          user_type: AUDIT_LDAP_USER,
          user_id: ldap_login,
          resource_type: AUDIT_RESERVED_LOGIN,
          resource_id: login,
          changes: []
      )

      History::AddAudit.add(audit)
    end

    def set_reservation
      authorize Reservation
      @reservation = Twitch::Reservation.find(params[:id])

      if @reservation.blank?
        flash[:error] = "Reservation with Login '#{params[:id]}' not found"
        redirect_to twitch_reservations_path
      end
    end
  end
end
