# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
# or more contributor license agreements. Licensed under the Elastic License;
# you may not use this file except in compliance with the Elastic License.

require "spec_helper"
require "logstash/json"
require "license_checker/license_manager"
require 'monitoring/monitoring'

class Observer
  attr_reader :xpack_info

  def initialize(xpack_info, is_serverless)
    @xpack_info = xpack_info
    @is_serverless = is_serverless
  end

  def update(xpack_info, is_serverless)
    @xpack_info = xpack_info
    @is_serverless = is_serverless
  end
end

describe LogStash::LicenseChecker::LicenseManager do
  let(:subject) { described_class.new(license_reader, 'monitoring') }
  let(:status) { "active"}
  let(:type) { 'trial' }

  let(:issue_date) { Time.now - ONE_DAY }
  let(:expiry_date) { Time.now + ONE_DAY }
  let(:max_nodes) { 1000 }
  let(:issued_to) { "logstasher" }
  let(:issuer) { "elasticsearch"}
  let(:start_date_in_millis) { -1 }
  let(:extension) { LogStash::MonitoringExtension.new }
  let(:system_settings) { LogStash::Runner::SYSTEM_SETTINGS.clone }
  let(:elasticsearch_url) { ["https://localhost:9898"] }
  let(:elasticsearch_username) { "elastictest" }
  let(:elasticsearch_password) { "testchangeme" }
  let(:license_reader) { double ('license_reader')}
  let(:license_status) { 'active'}
  let(:license_type) { 'trial' }
  let(:expiry_in_millis) { expiry_date.to_i * 1000 }
  let(:license_response) {
    LogStash::Json.load("{
              \"license\": {
                \"status\": \"#{license_status}\",
                \"uid\": \"9a48c67c-ce2c-4169-97bf-37d324b8ab80\",
                \"type\": \"#{license_type}\",
                \"issue_date\": \"2017-07-11T01:35:23.584Z\",
                \"issue_date_in_millis\": 1499736923584,
                \"expiry_date\": \"#{expiry_date.to_s}\",
                \"expiry_date_in_millis\": #{expiry_in_millis},
                \"max_nodes\": 1000,
                \"issued_to\": \"x-pack-elasticsearch_plugin_run\",
                \"issuer\": \"elasticsearch\",
                \"start_date_in_millis\": -1
              }
            }")
  }

  let(:settings) do
    {
        "xpack.monitoring.enabled" => true,
        "xpack.monitoring.elasticsearch.hosts" => elasticsearch_url,
        "xpack.monitoring.elasticsearch.username" => elasticsearch_username,
        "xpack.monitoring.elasticsearch.password" => elasticsearch_password,
    }
  end

  let(:license) do
      {
          "license" => {
          "status" => status,
          "uid" => SecureRandom.uuid,
          "type" => type,
          "issue_date" => issue_date,
          "issue_date_in_millis" => issue_date.to_i * 1000,
          "expiry_date" => expiry_date,
          "expiry_date_in_millis" => expiry_date.to_i * 1000,
          "max_nodes" => max_nodes,
          "issued_to" => issued_to,
          "issuer" => issuer,
          "start_date_in_millis" => start_date_in_millis
          }
      }
    end

  before do
    extension.additionals_settings(system_settings)
    apply_settings(settings, system_settings)
  end

  context 'observers' do
    let(:observer) { Observer.new(xpack_info, is_serverless) }
    let(:is_serverless) { false }
    let(:xpack_info) { LogStash::LicenseChecker::XPackInfo.from_es_response(license) }

    before(:each) do
      expect(license_reader).to receive(:fetch_cluster_info).and_return(cluster_info)
      expect(license_reader).to receive(:fetch_xpack_info).and_return(xpack_info)
      subject.add_observer(observer)
    end

    context 'when the type changes' do
      let(:new_type) { 'basic' }
      let(:second_license) do
        { 'license' => license['license'].merge({ 'type' => new_type })}
      end

      it 'updates observers' do
        expect(license_reader).to receive(:fetch_xpack_info).and_return LogStash::LicenseChecker::XPackInfo.from_es_response(second_license)

        expect(observer.xpack_info.license_type).to eq type
        subject.fetch_xpack_info
        expect(observer.xpack_info.license_type).to eq new_type
      end
    end

    context 'when the status changes' do
      let(:new_status) { 'expired' }
      let(:second_license) do
        { 'license' => license['license'].merge({ 'status' => new_status })}
      end
      it 'updates observers' do
        expect(license_reader).to receive(:fetch_xpack_info).and_return LogStash::LicenseChecker::XPackInfo.from_es_response(second_license)

        expect(observer.xpack_info.license_status).to eq status
        subject.fetch_xpack_info
        expect(observer.xpack_info.license_status).to eq new_status
      end
    end

    context 'when the license goes from not-loaded to loaded' do
      let(:xpack_info) { LogStash::LicenseChecker::XPackInfo.xpack_not_installed }

      it 'updates observers' do
        expect(license_reader).to receive(:fetch_xpack_info).and_return LogStash::LicenseChecker::XPackInfo.from_es_response(license)

        expect(observer.xpack_info).to eq LogStash::LicenseChecker::XPackInfo.xpack_not_installed
        subject.fetch_xpack_info
        expect(observer.xpack_info).to eq LogStash::LicenseChecker::XPackInfo.from_es_response(license)
      end
    end

    context 'when the license goes from loaded to not-loaded' do
      it 'updates observers' do
        expect(license_reader).to receive(:fetch_xpack_info).and_return LogStash::LicenseChecker::XPackInfo.xpack_not_installed

        expect(observer.xpack_info).to eq LogStash::LicenseChecker::XPackInfo.from_es_response(license)
        subject.fetch_xpack_info
        expect(observer.xpack_info).to eq LogStash::LicenseChecker::XPackInfo.xpack_not_installed
      end
    end
  end

  context "serverless" do
    context 'when fetch cluster info successfully' do
      let(:build_flavour) { 'serverless' }

      before(:each) do
        expect(license_reader).to receive(:fetch_cluster_info).and_return(cluster_info(LOGSTASH_VERSION, build_flavour)).at_most(:twice)
        expect(license_reader).not_to receive(:fetch_xpack_info)
      end

      it 'does not fetch xpack info' do
        subject.fetch_license
      end

      it 'checks build flavour' do
        expect(subject.serverless?).to be_truthy
      end
    end

    context 'when it fails to fetch cluster info' do
      let(:xpack_info) { LogStash::LicenseChecker::XPackInfo.from_es_response(license) }

      before(:each) do
        expect(license_reader).to receive(:fetch_cluster_info).and_return({})
        expect(license_reader).to receive(:fetch_xpack_info).and_return(xpack_info)
      end

      it 'checks build flavour' do
        expect(subject.serverless?).to be_falsey
      end
    end
  end
end
