require "rails_helper"

RSpec.describe Account do
  describe "associations" do
    it { is_expected.to have_many(:users).through(:account_auths) }
    it { is_expected.to have_many(:projects).dependent(:destroy) }
    it { is_expected.to have_many(:contract_templates).through(:projects) }
  end

  describe "validations" do
    it { is_expected.to validate_presence_of(:name) }
    it { is_expected.to validate_presence_of(:slug) }

    describe "#slug uniqueness" do
      subject { build(:account) }

      it "validates uniqueness of slug" do
        allow(subject).to receive(:set_slug)
        expect(subject).to validate_presence_of(:slug)
      end
    end
  end

  describe "generating a slug" do
    context "when name and slug are not present" do
      it "does not generate a slug" do
        account = build(:account, name: nil, slug: nil)

        account.save

        expect(account.slug).to be_nil
      end
    end

    context "when a name is present and a slug is not present" do
      it "generates a slug" do
        account = build(:account, name: "Half Pint Courter", slug: nil)

        account.save

        expect(account.slug).to eq "half-pint-courter"
      end
    end

    context "when name and slug are both present" do
      it "does not generate a slug" do
        account = build(:account, name: "Half Pint Courter", slug: "half-pint-courter2")

        account.save

        expect(account.slug).to eq "half-pint-courter2"
      end
    end

    context "when name is not unique" do
      it "generates a unique slug" do
        account_one = create(:account, name: "Half Pint Courter", slug: "half-pint-courter")
        account_two = create(:account, name: "Half Pint Courter", slug: "half-pint-courter-2")
        account_three = build(:account, name: "Half Pint Courter", slug: nil)

        account_three.save

        expect(account_three.slug).to eq "half-pint-courter-3"
      end
    end
  end

  describe "#storage_total" do
    it "sums videos, release photos, contracts, signatures, recordings" do
      video_file = Rack::Test::UploadedFile.new(Rails.root.join("spec", "fixtures", "files", "video_file.mp4"), "video/mp4")
      recording_file = Rack::Test::UploadedFile.new(Rails.root.join("spec", "fixtures", "files", "video_file.mp4"), "video/mp4")
      photo_file = Rack::Test::UploadedFile.new(Rails.root.join("spec", "fixtures", "files", "person_photo.png"), "image/png")
      contract_file = Rack::Test::UploadedFile.new(Rails.root.join("spec", "fixtures", "files", "contract.pdf"), "application/pdf")
      signature_file = Rack::Test::UploadedFile.new(Rails.root.join("spec", "fixtures", "files", "signature.png"), "image/png")
      edl_file = Rack::Test::UploadedFile.new(Rails.root.join("spec", "fixtures", "files", "sample-edl.edl"), "application/octet-stream")

      expect(video_file.size).to eq 1_055_736
      expect(recording_file.size).to eq 1_055_736
      expect(edl_file.size).to eq 440
      expect(photo_file.size).to eq 910
      expect(contract_file.size).to eq 12
      expect(signature_file.size).to eq 2_509

      account = create(:account)
      project = create(:project, account: account)
      video = create(:video, project: project, file: video_file, edl_file: edl_file)
      appearance_release = create(:appearance_release, project: project, person_photo: photo_file, contract: contract_file, signature: signature_file)
      talent_release = create(:talent_release, project: project, photos: [photo_file], contract: contract_file, signature: signature_file)
      material_release = create(:material_release, project: project, photos: [photo_file], contract: contract_file, signature: signature_file)
      location_release = create(:location_release, project: project, photos: [photo_file], contract: contract_file, signature: signature_file)
      acquired_media_release = create(:acquired_media_release, project: project, contract: contract_file)
      import = create(:import, project: project, file: contract_file)
      music_release = create(:music_release, project: project, contract: contract_file)
      zoom_meeting = create(:zoom_meeting, project: project, recording: recording_file)

      expect(account.storage_total).to eq 2_125_672
    end

    it "sums only for projects tied to account" do
      video_file = Rack::Test::UploadedFile.new(Rails.root.join("spec", "fixtures", "files", "video_file.mp4"), "video/mp4")
      edl_file = Rack::Test::UploadedFile.new(Rails.root.join("spec", "fixtures", "files", "sample-edl.edl"), "application/octet-stream")

      expect(video_file.size).to eq 1_055_736
      expect(edl_file.size).to eq 440

      account = create(:account)
      project = create(:project, account: account)
      other_account_project = create(:project, account: create(:account))
      create(:video, project: project, file: video_file, edl_file: edl_file)
      create(:video, project: other_account_project, file: video_file, edl_file: edl_file)

      expect(account.storage_total).to eq 1_056_176
    end

    it "fails when we do not account for models that have attachments" do
      models_with_attachments = [
        AppearanceRelease,
        TalentRelease,
        MaterialRelease,
        LocationRelease,
        AcquiredMediaRelease,
        Import,
        MusicRelease,
        Video,
        SampleAppearanceRelease,
        ActiveStorage::Blob,
        ActionText::RichText,
        Directory,
        Download,
        User,
        Broadcast,
        Account,
        ZoomMeeting,
        MedicalRelease,
        MatchingRequest
      ]
      Rails.application.eager_load!
      ActiveRecord::Base.descendants.each do |model|
        if model.reflections.keys.any? { |x| x.match? /_attachments?/ }
          unless models_with_attachments.include?(model)
            fail("Warning! #{model} may have an unaccounted for attachment, please add to #storage_total")
          end
        end
      end
    end
  end

  describe "#me_suite_enabled?" do
    it "returns true when plan_uid is me_suite" do
      expect(build(:account, plan_uid: "me_suite").me_suite_enabled?).to eq true
    end

    it "returns false when plan_uid is not me_suite" do
      expect(build(:account, plan_uid: "deliverme").me_suite_enabled?).to eq false
    end
  end

  describe "#deliverme_enabled?" do
    it "returns true when plan_uid is me_suite" do
      expect(build(:account, plan_uid: "me_suite").deliverme_enabled?).to eq true
    end

    it "returns true when plan_uid is deliverme" do
      expect(build(:account, plan_uid: "deliverme").deliverme_enabled?).to eq true
    end

    it "returns false when plan_uid is not deliverme" do
      expect(build(:account, plan_uid: "releaseme").deliverme_enabled?).to eq false
    end
  end

  describe "#directme_enabled?" do
    it "returns true when plan_uid is me_suite" do
      expect(build(:account, plan_uid: "me_suite").directme_enabled?).to eq true
    end

    it "returns true when plan_uid is directme" do
      expect(build(:account, plan_uid: "directme").directme_enabled?).to eq true
    end

    it "returns false when plan_uid is not directme" do
      expect(build(:account, plan_uid: "releaseme").directme_enabled?).to eq false
    end
  end

  describe "#releaseme_enabled?" do
    it "returns true when plan_uid is me_suite" do
      expect(build(:account, plan_uid: "me_suite").releaseme_enabled?).to eq true
    end

    it "returns true when plan_uid is releaseme" do
      expect(build(:account, plan_uid: "releaseme").releaseme_enabled?).to eq true
    end

    it "returns false when plan_uid is not releaseme" do
      expect(build(:account, plan_uid: "deliverme").releaseme_enabled?).to eq false
    end
  end

  describe "#plan_name" do
    context "when plan_uid deliverme" do
      it "returns DeliverME" do
        expect(build(:account, plan_uid: "deliverme").plan_name).to eq "DeliverME"
      end
    end

    context "when plan_uid directme" do
      it "returns DirectME" do
        expect(build(:account, plan_uid: "directme").plan_name).to eq "DirectME"
      end
    end

    context "when plan_uid releaseme" do
      it "returns ReleaseME" do
        expect(build(:account, plan_uid: "releaseme").plan_name).to eq "ReleaseME"
      end
    end

    context "when plan_uid me_suite" do
      it "returns ME Suite" do
        expect(build(:account, plan_uid: "me_suite").plan_name).to eq "ME Suite"
      end
    end
  end

  describe "#managers" do
    it "returns users who have the account manager role" do
      account = build(:account)
      account_manager = create(:user, :account_manager, accounts: [account])
      project_manager = create(:user, :manager, accounts: [account])

      managers = account.managers

      expect(managers).to include(account_manager)
      expect(managers).not_to include(project_manager)
    end
  end
end
