require 'rails_helper'

RSpec.describe MaterialSyncImporter do
  let(:user) { create(:user, :member) }
  let(:tag) { Tag.create!(tag_name: TagName.create!(name: 'sync_tag'), category: :material) }

  def tempfile_for body
    Tempfile.new(['material-sync-importer', '.png']).tap do |file|
      file.binmode
      file.write(body)
      file.rewind
    end
  end

  it 'creates an untagged material from a sync candidate with file_downloader' do
    result =
        described_class.import!(
            source_kind: 'google_drive_file',
            source_path: '素材/a.png',
            source_file_id: 'drive-file-a',
            normalized_source_key: 'google_drive_file:drive-file-a',
            filename: 'a.png',
            content_type: 'image/png',
            file_sha256: Digest::SHA256.hexdigest('sync-body'),
            file_downloader: -> { tempfile_for('sync-body') },
            export_path: '素材/a.png',
            tag: nil,
            url: nil,
            created_by_user: user,
            updated_by_user: user)

    material = result.material.reload
    expect(result.action).to eq(:imported)
    expect(material.tag).to be_nil
    expect(material.url).to be_nil
    expect(material.file).to be_attached
    expect(material.file.blob.filename.to_s).to eq('a.png')
    expect(material.material_export_items.first.export_path).to eq('素材/a.png')
  end

  it 'does not clear a human-assigned tag or URL on existing Drive sync' do
    material =
        Material.create!(tag:, url: 'https://example.com/human',
                         source_kind: 'google_drive_file',
                         source_path: '素材/a.png',
                         source_file_id: 'drive-file-a',
                         created_by_user: user,
                         updated_by_user: user)
    material.file.attach(
        io: StringIO.new('same-body'),
        filename: 'a.png',
        content_type: 'image/png')
    material.file.blob.metadata['sha256'] = Digest::SHA256.hexdigest('same-body')
    material.file.blob.save!
    MaterialExportItem.create!(material:,
                               profile: 'legacy_drive',
                               export_path: '素材/a.png',
                               created_by_user: user)

    result =
        described_class.import!(
            source_kind: 'google_drive_file',
            source_path: '素材/a.png',
            source_file_id: 'drive-file-a',
            filename: 'a.png',
            content_type: 'image/png',
            file_sha256: Digest::SHA256.hexdigest('same-body'),
            export_path: '素材/a.png',
            tag: nil,
            url: nil,
            updated_by_user: user)

    expect(result.action).to eq(:unchanged)
    expect(material.reload.tag).to eq(tag)
    expect(material.url).to eq('https://example.com/human')
  end

  it 'suppresses a Google Drive candidate by relative path prefix' do
    MaterialSyncSuppression.create!(source_kind: 'google_drive_path_prefix',
                                    drive_path: '素材/危険',
                                    reason: 'copyright_high_risk',
                                    created_by_user: user)

    result =
        described_class.import!(
            source_kind: 'google_drive_file',
            source_path: '素材/危険/a.png',
            source_file_id: 'drive-file-b',
            filename: 'a.png',
            content_type: 'image/png',
            file_sha256: Digest::SHA256.hexdigest('blocked-body'),
            file_downloader: -> { tempfile_for('blocked-body') },
            export_path: '素材/危険/a.png',
            updated_by_user: user)

    expect(result.action).to eq(:suppressed)
    expect(result.suppression.normalized_source_key)
      .to eq('google_drive_path_prefix:素材/危険')
    expect(Material.find_by(source_file_id: 'drive-file-b')).to be_nil
  end

  it 'rechecks import blocks after downloaded file sha256 is known' do
    MaterialImportBlock.create!(match_kind: 'sha256',
                                sha256: Digest::SHA256.hexdigest('blocked-body'),
                                reason: 'copyright_high_risk',
                                created_by_user: user)
    blob_count = ActiveStorage::Blob.count

    expect do
      result =
          described_class.import!(
              source_kind: 'google_drive_file',
              source_path: '素材/blocked.png',
              source_file_id: 'drive-file-blocked',
              filename: 'blocked.png',
              content_type: 'image/png',
              file_downloader: -> { tempfile_for('blocked-body') },
              export_path: '素材/blocked.png',
              updated_by_user: user)

      expect(result.action).to eq(:suppressed)
      expect(result.suppression.reason).to eq('copyright_high_risk')
    end.not_to change(Material, :count)

    expect(ActiveStorage::Blob.count).to eq(blob_count)
    expect(Material.find_by(source_file_id: 'drive-file-blocked')).to be_nil
  end
end
