# frozen_string_literal: true

require "rails_helper"
require "support/example_exporter"
require "base64"

# This only tests the exporter itself to make sure zip file creation works.
RSpec.describe Exporter do
  include ActiveSupport::Testing::TimeHelpers

  let(:user) { FactoryBot.create(:user, screen_name: "fizzyraccoon", export_processing: true) }
  let(:instance) { described_class.new(user) }
  let(:zipfile_deletion_expected) { false }

  before do
    stub_const("APP_CONFIG", {
      "site_name"      => "justask",
      "hostname"       => "example.com",
      "https"          => true,
      "items_per_page" => 5,
      "fog"            => {}
    }.with_indifferent_access)
  end

  after do
    filename = instance.instance_variable_get(:@zipfile)&.name
    unless File.exist?(filename)
      warn "exporter_spec.rb: wanted to clean up #{filename.inspect} but it does not exist!" unless zipfile_deletion_expected
      next
    end
    FileUtils.rm_r(filename)
  end

  describe "#export" do
    let(:export_name) { instance.instance_variable_get(:@export_name) }

    subject do
      travel_to(Time.utc(2022, 12, 10, 13, 37, 42)) do
        instance.export
      end
    end

    before do
      allow(UseCase::DataExport::Base)
        .to receive(:descendants)
        .and_return([ExampleExporter])
    end

    it "creates a zip file with the expected contents" do
      subject

      # check created zip file
      zip_path = Rails.public_path.join("export/#{export_name}.zip")
      expect(File.exist?(zip_path)).to be true

      Zip::File.open(zip_path) do |zip|
        # check for zip comment
        expect(zip.comment).to eq "justask export done for fizzyraccoon on 2022-12-10T13:37:42Z\n"

        # check if all files and directories are there
        expect(zip.entries.map(&:name).sort).to eq([
          # basic dirs from exporter
          "#{export_name}/",
          "#{export_name}/pictures/",
          # files added by the ExampleExporter
          "#{export_name}/textfile.txt",
          "#{export_name}/pictures/example.jpg",
          "#{export_name}/some.json"
        ].sort)

        # check if the file contents match
        expect(zip.file.read("#{export_name}/textfile.txt")).to eq("Sample Text\n")
        expect(Base64.encode64(zip.file.read("#{export_name}/pictures/example.jpg")))
          .to eq(Base64.encode64(File.read(File.expand_path("../fixtures/files/banana_racc.jpg", __dir__))))
        expect(zip.file.read("#{export_name}/some.json")).to eq(<<~JSON)
          {
            "animals": [
              "raccoon",
              "fox",
              "hyena",
              "deer",
              "dog"
            ],
            "big_number": 3457812374589235798,
            "booleans": {
              "yes": true,
              "no": false,
              "file_not_found": null
            }
          }
        JSON
      end
    end

    it "updates the export fields of the user" do
      expect { subject }.to change { user.export_processing }.from(true).to(false)
      expect(user.export_url).to eq("https://example.com/export/#{export_name}.zip")
      expect(user.export_created_at).to eq(Time.utc(2022, 12, 10, 13, 37, 42))
      expect(user).to be_persisted
    end

    context "when exporting fails" do
      let(:zipfile_deletion_expected) { true }

      before do
        allow_any_instance_of(ExampleExporter).to receive(:files).and_raise(ArgumentError.new("just testing"))
      end

      it "deletes the zip file" do
        expect { subject }.to raise_error(ArgumentError, "just testing")

        zip_path = Rails.public_path.join("export/#{export_name}.zip")
        expect(File.exist?(zip_path)).to be false
      end
    end
  end
end