require 'csv'

module Twitch
  class UsersController < Twitch::BaseController
    include AttributeReadAuthorized

    before_action :set_user, except: [:index]

    def index
      respond_to do |format|
        format.html do
          set_users
          @users = @users.page(params[:page]).per_page(params[:per_page])
          @users = @users.all.each { |user| redact_attributes(user) }
          page = (params[:page].presence || 1).to_i
          redirect_to @users.first if @users.length == 1 && page == 1
          track_action! trackable_request.assemble_an.admin_panel_user_search(query: params[:text])
        end

        format.csv do
          authorize User, :dump?
          set_users
          @users = @users.all(skip_pagination: true)

          send_data users_to_csv, filename: "users-#{Date.today}.csv"
        end
      end
    end

    def show
      begin
        connections = PlatformConnections::Connection.get_all(params[:id])

        if youtube_id = connections[Connections::YOUTUBE].connection_details.try(:[], "youtube_id")
          @youtube_url = "https://www.youtube.com/channel/#{youtube_id}"
        end

        @user_connections = connections.each_with_object({}){|connection, hash|
          hash[connection[0]] = connection[1].has_connection
        }
      rescue Faraday::ClientError => e
        @connections_error = e
      end

      @can_edit_roles = current_user.permitted?(BeefCake::Permission.for(:staff_admins_global_mods))
      @can_edit_validated_non_partner = current_user.permitted?(BeefCake::Permission.for(:manage_validated_non_partner))
      @platforms = PlatformConnections::CONNECTION_PLATFORMS
      today = Time.now
      @window_start = today - 7.days
      @window_end = today
      begin
        @takedowns = @user.dmca_strikes_received(@window_start, @window_end)
      rescue Faraday::ClientError => e
        @takedowns_error = e
      end

      @aegis_report_clips_url = "https://aegis.xarth.tv/reportclipsearch/?targetUserID=#{params[:id]}"
      @report_clips = SupportTools::AegisGateway.report_clip_count(params[:id])

      begin
        @sessions = Sessions::Cookies.list(@user.id)
      rescue Faraday::ClientError => e
        @sessions_error = e
      end

      begin
        memberships, rbac_error = @user.find_rbac_memberships
        if !rbac_error.nil?
          @find_rbac_memberships_error = rbac_error
        else
          @is_developer_admin_results = Hash[memberships.map { |company_id, membership| [company_id, membership.role == Rbac::Membership::ROLE_ADMIN || membership.role == Rbac::Membership::ROLE_BILLING_MANAGER || membership.role == Rbac::Membership::ROLE_OWNER] }]
          @is_shadow_account_results = Hash[memberships.map { |company_id, membership| [company_id, membership.role == Rbac::Membership::ROLE_SHADOW_ACCOUNT] }]
          @token_balance = Subscriptions::Token.get_token_balance(@user.id)
        end
      rescue Faraday::ClientError => e
        @find_rbac_memberships_error = e
      end
    end

    def update
      user = params[:twitch_user]
      return false if user.blank?
      if user[:redirect_channel].present? || user[:mature_channel].present? || user[:directory_hidden].present? || user[:privacy_options_enabled].present? || user[:private_video].present?
        channel_results = @user.channel_results
        response = @user.update_channel(params)
        if response.success?
          audit_channel_update(user, channel_results)
          flash[:success] = "Successfully modified channel #{@user.login}"
        else
          flash[:error] = "#{response.body['message']}. Channel could not be updated."
        end
      else
        response = @user.update(params)
        if response.success?
          audit_user_update(user)
          flash[:success] = "Successfully modified #{@user.login}"
        else
          flash[:error] = "#{response.body['message']}. User could not be updated."
        end
      end
      redirect_to @user
    end

    def undelete
      flagged_for_rename = @user.flagged_for_rename? || false
      response = @user.undelete(current_user.ldap_login)
      if response.success?
        flash[:success] = "Successfully reactivated #{@user.login}."
        flash[:success] << " Username reset requirement lifted." if flagged_for_rename
      else
        flash[:error] = "#{response.body['message']}. User could not be reactivated."
      end
      redirect_to @user
    end

    def soft_delete
      flagged_for_rename = params[:flagged_for_rename].present?
      response = @user.soft_delete(current_user.ldap_login, flagged_for_rename)
      if response.success?
        flash[:success] = "Successfully deactivated #{@user.login}."
        flash[:success] << " Username reset required on next login." if flagged_for_rename
      else
        flash[:error] = "#{response.body['message']}. User could not be deactivated."
      end
      redirect_to @user
    end

    def hard_delete
      if @user.deleted_on.nil?
        flash[:error] = "User must be deactivated before hard deletion"
        redirect_to @user
      end
    end

    def destroy
      response = @user.hard_delete(current_user.ldap_login)
      if response.success?
        flash[:success] = "Successfully hard deleted #{@user.login}"
        redirect_to @user
      else
        flash[:error] = "#{response.body['message']}. User could not be hard deleted."
        redirect_back and return
      end
    end

    def set_users
      authorize User
      @users = User.scoped

      [:text, :email, :ip].each do |field|
        @users = @users.where(field => params[field]) if params[field].present?
      end
    end

    def compare_geo_ip
      historic_ips = History::QueryAudit.ips_for_twitch_user(@user.id)
      @match_result = IpComparison.compare_ips(params[:geo_ip], historic_ips)
      @candidate_ip_geo = IpComparison.geo_lookup_ip(params[:geo_ip])

      track_action! trackable_request.assemble_an.admin_panel_profile_geoip_submit(user_id: params[:id], geoip_entry: params[:geo_ip])

      render partial: 'twitch/users/sidebars/geoip'
    end

    def disable_twitchguard
      audit = History::Audit.new(
        action: History::AUDIT_ACTION_DISABLE_TWITCHGUARD,
        user_type: History::AUDIT_LDAP_USER,
        user_id: current_user.ldap_login,
        resource_type: History::AUDIT_TWITCH_USER,
        resource_id: @user.id,
        changes: []
      )
      History::AddAudit.add(audit)

      success = @user.disable_twitchguard!

      if success
        flash[:success] = 'Successfully disabled TwitchGuard'
      else
        flash[:danger] = 'Failed to disable TwitchGuard'
      end

      redirect_to @user
    end

    protected

    def users_to_csv
      attributes = [:id, :login, :email, :remote_ip, :created_on, :last_login]
      CSV.generate do |csv|
        csv << attributes + [:status]
        @users.each do |user|
          csv << attributes.map { |attr| user.attributes[attr] } + [user.status.join('& ')]
        end
      end
    end

    def set_user
      @user = User.find params[:id]

      if @user.blank?
        flash[:error] = "User not found"
        redirect_to twitch_users_path
        return
      end

      authorize @user
      @user = redact_attributes(@user)
    end

    def user_params
      params.require(:twitch_user).permit(role_ids: [])
    end

    def audit_user_update(user)
      update_attributes = [
        :description,
        :displayname,
        :email,
        :phone_number,
        :category,
        :birthday,
        :language,
        :deletion_hold,
        :enable_email_reuse
      ]
      changes = []
      update_attributes.each do |key|
        symbol = key.to_sym
        old_value = @user.send key
        if old_value != user[symbol]
          change = History::ChangeSet.new(
              attribute: symbol,
              old_value: old_value,
              new_value: user[symbol]
          )
          changes.push(change)
        end
      end

      return if changes.length.zero?

      audit = History::Audit.new(
          action: History::AUDIT_ACTION_UPDATE,
          user_type: History::AUDIT_LDAP_USER,
          user_id: current_user.ldap_login,
          resource_type: History::AUDIT_TWITCH_USER,
          resource_id: @user.id,
          changes: changes
      )

      History::AddAudit.add(audit)
    end

    def audit_channel_update(user, channel_results)
      update_attributes = [:redirect_channel, :mature_channel, :directory_hidden]
      changes = []
      update_attributes.each do |key|
        symbol = key.to_s
        value = user[symbol]
        if key == :mature_channel
          old_value = channel_results["mature"] || false
          value = true?(value)
        elsif key == :directory_hidden
          old_value = channel_results[symbol] || false
          value = true?(value)
        else
          old_value = channel_results[symbol]
        end

        if old_value != value
          change = History::ChangeSet.new(
              attribute: symbol,
              old_value: old_value,
              new_value: value
          )
          changes.push(change)
        end
      end

      return if changes.length.zero?

      audit = History::Audit.new(
          action: History::AUDIT_ACTION_UPDATE,
          user_type: History::AUDIT_LDAP_USER,
          user_id: current_user.ldap_login,
          resource_type: History::AUDIT_TWITCH_USER,
          resource_id: @user.id,
          changes: changes
      )

      History::AddAudit.add(audit)
    end

    def true?(obj)
      obj.to_s == "true"
    end
  end
end
