require 'spec_helper'

RSpec.describe 'CSS URL Rewriting' do
  let(:site) { create_test_site }
  let(:context) { create_liquid_context(site) }
  let(:skyhook) { Jekyll::Skyhook.instance(site) }

  after do
    FileUtils.rm_rf(site.source)
    FileUtils.rm_rf(site.dest)
    FileUtils.rm_rf(site.cache_dir)
  end

  describe 'url() rewriting in CSS files' do
    it 'rewrites relative image URLs to digested paths' do
      # Create referenced image
      create_test_image(site, 'assets/images/bg.jpg')

      # Create CSS with relative URL
      css_content = <<~CSS
        .header {
          background: url('images/bg.jpg') no-repeat;
        }
      CSS
      create_test_css(site, 'assets/styles.css', css_content)

      # Process assets
      skyhook.process_assets

      # Read the processed CSS file
      tag = create_tag(Jekyll::Tags::AssetTag, 'assets/styles.css')
      digested_css_path = tag.render(context)
      full_css_path = File.join(site.source, digested_css_path[1..-1]) # Remove leading slash

      processed_css = File.read(full_css_path)

      # Should rewrite to digested path
      expect(processed_css).to include('url(/_digested/assets/images/bg-')
      expect(processed_css).to include('.jpg)')
      expect(processed_css).not_to include("url('images/bg.jpg')")
    end

    it 'rewrites URLs with different quote styles' do
      create_test_image(site, 'assets/logo.png')

      css_content = <<~CSS
        .element1 { background: url('logo.png'); }
        .element2 { background: url("logo.png"); }
        .element3 { background: url(logo.png); }
      CSS
      create_test_css(site, 'assets/main.css', css_content)

      skyhook.process_assets

      tag = create_tag(Jekyll::Tags::AssetTag, 'assets/main.css')
      digested_css_path = tag.render(context)
      full_css_path = File.join(site.source, digested_css_path[1..-1])

      processed_css = File.read(full_css_path)

      # All should be rewritten to digested paths
      expect(processed_css.scan(/url\(.*?logo.*?\)/).length).to eq(3)
      expect(processed_css).to include('url(/_digested/assets/logo-')
      expect(processed_css).not_to include('url(logo.png)')
      expect(processed_css).not_to include('url("logo.png")')
      expect(processed_css).not_to include("url('logo.png')")
    end

    it 'handles nested directory structures' do
      # Create assets in different directories
      create_test_image(site, 'assets/images/icons/close.svg')
      create_test_image(site, 'assets/fonts/icons.woff')

      css_content = <<~CSS
        .close-btn {
          background: url('../images/icons/close.svg');
        }

        @font-face {
          src: url('../fonts/icons.woff');
        }
      CSS
      create_test_css(site, 'assets/css/components.css', css_content)

      skyhook.process_assets

      tag = create_tag(Jekyll::Tags::AssetTag, 'assets/css/components.css')
      digested_css_path = tag.render(context)
      full_css_path = File.join(site.source, digested_css_path[1..-1])

      processed_css = File.read(full_css_path)

      expect(processed_css).to include('url(/_digested/assets/images/icons/close-')
      expect(processed_css).to include('url(/_digested/assets/fonts/icons-')
      expect(processed_css).not_to include("url('../images/icons/close.svg')")
      expect(processed_css).not_to include("url('../fonts/icons.woff')")
    end

    it 'preserves absolute URLs and external URLs' do
      css_content = <<~CSS
        .element1 { background: url('/absolute/path.jpg'); }
        .element2 { background: url('https://example.com/external.png'); }
        .element3 { background: url('http://cdn.example.com/image.gif'); }
        .element4 { background: url('//protocol-relative.com/image.svg'); }
      CSS
      create_test_css(site, 'assets/external.css', css_content)

      skyhook.process_assets

      tag = create_tag(Jekyll::Tags::AssetTag, 'assets/external.css')
      digested_css_path = tag.render(context)
      full_css_path = File.join(site.source, digested_css_path[1..-1])

      processed_css = File.read(full_css_path)

      # These should remain unchanged
      expect(processed_css).to include("url('/absolute/path.jpg')")
      expect(processed_css).to include("url('https://example.com/external.png')")
      expect(processed_css).to include("url('http://cdn.example.com/image.gif')")
      expect(processed_css).to include("url('//protocol-relative.com/image.svg')")
    end

    it 'handles missing referenced assets gracefully' do
      css_content = <<~CSS
        .header {
          background: url('missing-image.jpg');
        }
        .existing {
          background: url('logo.png');
        }
      CSS

      create_test_image(site, 'assets/logo.png')
      create_test_css(site, 'assets/mixed.css', css_content)

      skyhook.process_assets

      tag = create_tag(Jekyll::Tags::AssetTag, 'assets/mixed.css')
      digested_css_path = tag.render(context)
      full_css_path = File.join(site.source, digested_css_path[1..-1])

      processed_css = File.read(full_css_path)

      # Missing image URL should remain unchanged
      expect(processed_css).to include("url('missing-image.jpg')")

      # Existing image should be rewritten
      expect(processed_css).to include('url(/_digested/assets/logo-')
      expect(processed_css).not_to include("url('logo.png')")
    end

    it 'handles complex CSS with multiple url() declarations' do
      create_test_image(site, 'assets/bg-1.jpg')
      create_test_image(site, 'assets/bg-2.png')
      create_test_image(site, 'assets/icon.svg')

      css_content = <<~CSS
        .multi-bg {
          background:
            url('bg-1.jpg') no-repeat top left,
            url('bg-2.png') repeat-x bottom,
            linear-gradient(to bottom, #fff, #eee);
        }

        .icon::before {
          content: '';
          background: url('icon.svg') center/contain;
        }

        /* Comment with url('fake.jpg') should not be processed */
      CSS
      create_test_css(site, 'assets/complex.css', css_content)

      skyhook.process_assets

      tag = create_tag(Jekyll::Tags::AssetTag, 'assets/complex.css')
      digested_css_path = tag.render(context)
      full_css_path = File.join(site.source, digested_css_path[1..-1])

      processed_css = File.read(full_css_path)

      # All real URLs should be rewritten
      expect(processed_css).to include('url(/_digested/assets/bg-1-')
      expect(processed_css).to include('url(/_digested/assets/bg-2-')
      expect(processed_css).to include('url(/_digested/assets/icon-')

      # Original URLs should be gone
      expect(processed_css).not_to include("url('bg-1.jpg')")
      expect(processed_css).not_to include("url('bg-2.png')")
      expect(processed_css).not_to include("url('icon.svg')")

      # CSS should not contain the fake URL from the comment
      expect(processed_css).not_to include("fake.jpg")
    end
  end

  describe 'CSS asset processing order' do
    it 'processes referenced images before rewriting CSS URLs' do
      create_test_image(site, 'assets/header-bg.jpg')

      css_content = <<~CSS
        .header {
          background: url('header-bg.jpg');
        }
      CSS
      create_test_css(site, 'assets/styles.css', css_content)

      # Process all assets
      skyhook.process_assets

      # Get the manifest
      manifest_path = File.join(site.cache_dir, 'skyhook', 'assets-manifest.json')
      manifest = JSON.parse(File.read(manifest_path))

      # Both assets should be in manifest
      expect(manifest.keys).to include('assets/header-bg.jpg')
      expect(manifest.keys).to include('assets/styles.css')

      # CSS should reference the digested image
      css_digested_path = manifest['assets/styles.css']
      full_css_path = File.join(site.source, css_digested_path)
      processed_css = File.read(full_css_path)

      image_digested_path = manifest['assets/header-bg.jpg']
      expect(processed_css).to include("url(/#{image_digested_path})")
    end
  end
end
