class PasswordsController < ApplicationController
  skip_before_action :enforce_password_reset!
  skip_before_action :authenticate_request!, except: :update
  skip_before_action :enforce_terms_of_service_agreement!

  def update
    return unless validate_password

    validate_confirmation_password

    if current_user.update(encrypted_password: params[:password], password_alert: false)
      render_success :ok
    else
      render_error :unprocessable_entity, errors: current_user
    end
  end

  def reset
    user_emails.each { |e| send_password_reset_email(e) }
    render_success :ok, message: 'Email has been sent.'
  end

  def token_valid
    if ::Password::RecoveryService.call(params[:token])
      render_success :ok
    else
      render_error :unprocessable_entity
    end
  end

  def recover
    user = ::Password::RecoveryService.call(params[:token])

    validate_confirmation_password(user)
    user&.assign_attributes(encrypted_password: params[:password], pw_recovery_time: '')

    if user&.save
      render_success :ok, message: 'Password updated.', json: { school_id: user.school_id }
    else
      errors = user || { token: 'no user found for this token' }
      render_error :unprocessable_entity, errors: errors
    end
  end

  private
    def validate_confirmation_password(user={})
      return if params[:confirm_password] == params[:password]

      user = current_user || user
      user&.add_custom_error(:confirm_password, 'must match password')
    end

    def validate_password
      if current_user.valid_password?(params[:current_password]) || current_user.password_alert?
        return true
      end

      render_error :unprocessable_entity, message: 'Password change failed'
      false
    end

    def reset_user
      @reset_user ||= school.users.find_by(username: params[:username])
    end

    def school
      @school ||= School.find_by(id: params[:school_id])
    end

    def user_emails
      return [] if reset_user.nil?
      return reset_user.family.primary_contact_emails if reset_user.role == :family

      [reset_user.user_model_association.email].compact
    end

    def template_variables
      @template_variables ||= {
        school_name: school.name,
        school_address: school.decorate.address_line,
        school_phone: school.phone,
        reset_url: recovery_url
      }
    end

    def send_password_reset_email(user_email)
      Mailgun::TemplateService.call(
        'Sycamore School <noreply@sycamoreschool.com>',
        user_email,
        'Reset your password',
        'password-reset',
        { variables: template_variables, tags: [school.id.to_s, 'passwordreset'] }
      )
    end

    def recovery_url
      time = DateTime.now

      reset_user.update(pw_recovery_time: time)

      payload = { uid: reset_user.id, pw_recovery_time: time }.to_json
      secrets = Rails.application.secrets
      token = JWT.encode payload, secrets.secret_key_base

      "#{secrets.vue_base_url}/password_recovery?token=#{token}"
    end
end
