require 'jekyll'
require 'rspec/helper'
require 'rspec'
require 'tempfile'

TestPage = Struct.new(:data, :url, :relative_path)

describe Site do
  before do
    @config = Jekyll::Configuration::DEFAULTS.dup
    @langs = ['en', 'sp', 'fr', 'de']
    @default_lang = 'en'
    @exclude_from_localization = ['javascript/', 'images/', 'css/', 'readme']
    @config['langs'] = @langs
    @config['default_lang'] = @default_lang
    @config['exclude_from_localization'] = @exclude_from_localization
    @parallel_localization = @config['parallel_localization'] || true

    @site = Site.new(
      Jekyll.configuration(
        'languages'                 => @langs,
        'default_lang'              => @default_lang,
        'exclude_from_localization' => @exclude_from_localization,
        'source'                    => File.expand_path('fixtures', __dir__),
        'url'                       => 'https://test.github.io'
      )
    )
    @site.prepare
    @baseurls = ['/polyglot', '/big-brother', '/bas3url2']
    @urls = ['http://localhost:4000', 'https://test.github.io']
    @document_url_regex = @site.document_url_regex
    @relative_url_regex = @site.relative_url_regex
    # @relativize_absolute_urls = @site.relativize_absolute_urls
    # @relativize_urls = @site.relativize_urls
  end

  describe @document_url_regex do
    it 'must match common default urls made by jekyll' do
      @langs.each do |lang|
        expect(@document_url_regex).to match "/#{lang}/foobar"
        expect(@document_url_regex).to match ".#{lang}/foobar"
        expect(@document_url_regex).to match "foobar.#{lang}/"
      end
    end
    it 'expect not match natural unfortunate urls' do
      expect(@document_url_regex).to_not match 'people/karen/foobar/'
      expect(@document_url_regex).to_not match 'verbs/gasp/foobar'
      expect(@document_url_regex).to_not match 'products/kefr/foobar.html'
      expect(@document_url_regex).to_not match 'properties/beachside/foo'
    end
    it 'expect relativized_urls should handle different output' do
      expected = 'expected'
      collection_test = Jekyll::Collection.new(@site, 'test')
      document = Jekyll::Document.new('about.en.md', site: @site, collection: collection_test)
      document.output = expected
      @site.relativize_urls(document, @relative_url_regex)
      expect(document.output).to eq(expected)

      # strings can be frozen and still relativized
      document.output.freeze
      @site.relativize_urls(document, @relative_url_regex)
      expect(document.output).to eq(expected)
    end
  end

  describe @parallel_localization do
    it 'should default to true if parallel_localization if not set' do
      expect(@parallel_localization).to eq(true)
    end
    it 'should be false if explicitly set' do
      @config['parallel_localization'] = false
      @parallel_localization = @config['parallel_localization']
      expect(@parallel_localization).to eq(false)
    end
  end

  describe @relative_url_regex do
    it 'must match certain strings with any simple baseurl' do
      @baseurls.each do |baseurl|
        @site.baseurl = baseurl
        @relative_url_regex = @site.relative_url_regex
        expect(@relative_url_regex).to match "href=\"#{baseurl}/about/\""
        expect(@relative_url_regex).to match "href=\"#{baseurl}/about-the-product/\""
        expect(@relative_url_regex).to match "href=\"#{baseurl}/2016/all-new-flavors/\""
        expect(@relative_url_regex).to match "href=\"#{baseurl}/words-1-with-2-numbers-34/\""
        expect(@relative_url_regex).to match "href=\"#{baseurl}/\""
        expect(@relative_url_regex).to match "href=\"#{baseurl}/purchase/product/1234-business\""
        expect(@relative_url_regex).to match "href=\"#{baseurl}/#about\""
        expect(@relative_url_regex).to match "href=\"#{baseurl}/about/#team\""
      end
    end
    it 'must match with an empty baseurl' do
      @relative_url_regex = @site.relative_url_regex
      expect(@relative_url_regex).to match 'href="/about/"'
      expect(@relative_url_regex).to match 'href="/about-the-product/"'
      expect(@relative_url_regex).to match 'href="/2016/all-new-flavors/"'
      expect(@relative_url_regex).to match 'href="/2016/words-1-with-2-numbers-34/"'
      expect(@relative_url_regex).to match 'href="/"'
      expect(@relative_url_regex).to match 'href="/purchase/product/1234-business"'
      expect(@relative_url_regex).to match 'href="/#about"'
      expect(@relative_url_regex).to match 'href="/about/#team"'
    end
    it 'must not match external urls' do
      @relative_url_regex = @site.relative_url_regex
      expect(@relative_url_regex).to_not match 'href="http://github.com"'
      expect(@relative_url_regex).to_not match 'href="https://talk.jekyllrb.com'
      expect(@relative_url_regex).to_not match 'href="http://google.com"'
      expect(@relative_url_regex).to_not match 'href="https://untra.github.io/polyglot"'
    end
    it 'must not match excluded urls' do
      @site.exclude += @exclude_from_localization
      @relative_url_regex = @site.relative_url_regex
      expect(@relative_url_regex).to_not match 'href="/images/my-vacation-photo.jpg"'
      expect(@relative_url_regex).to_not match 'href="/css/stylesheet.css"'
      expect(@relative_url_regex).to_not match 'href="/readme"'
      expect(@relative_url_regex).to_not match 'href="/javascript/65487-app.js"'
    end
    it 'must not match excluded urls with a set baseurl' do
      @baseurls.each do |baseurl|
        @site.baseurl = baseurl
        @site.exclude += @exclude_from_localization
        @relative_url_regex = @site.relative_url_regex
        expect(@relative_url_regex).to_not match "href=\"#{baseurl}/javascript/65487-app.js\""
        expect(@relative_url_regex).to_not match "href=\"#{baseurl}/images/my-vacation-photo.jpg\""
        expect(@relative_url_regex).to_not match "href=\"#{baseurl}/css/stylesheet.css\""
      end
    end
    it 'must not match localized urls' do
      @relative_url_regex = @site.relative_url_regex
      @langs.each do |lang|
        expect(@relative_url_regex).to_not match "href=\"#{lang}/about/\""
        expect(@relative_url_regex).to_not match "href=\"#{lang}/\""
        expect(@relative_url_regex).to_not match "href=\"#{lang}/purchase/product/1234-business\""
        expect(@relative_url_regex).to_not match "href=\"#{lang}/#about\""
        expect(@relative_url_regex).to_not match "href=\"#{lang}/about/#team\""
      end
    end

    it 'must not match localized urls with a set baseurl' do
      @baseurls.each do |baseurl|
        @site.baseurl = baseurl
        @site.exclude += @exclude_from_localization
        @relative_url_regex = @site.relative_url_regex
        expect(@relative_url_regex).to_not match "href=\"#{baseurl}/javascript/65487-app.js\""
        expect(@relative_url_regex).to_not match "href=\"#{baseurl}/images/my-vacation-photo.jpg\""
        expect(@relative_url_regex).to_not match "href=\"#{baseurl}/css/stylesheet.css\""
      end
    end

    it 'must not match excluded urls with glob patterns' do
      # Test with glob pattern in exclude_from_localization
      @site.config['exclude_from_localization'] = ['*.sublime-workspace', '*.pdf', '.github']
      @site.prepare
      @site.exclude += @site.exclude_from_localization
      @relative_url_regex = @site.relative_url_regex

      # These should NOT match because they match the glob pattern
      expect(@relative_url_regex).to_not match 'href="/my-project.sublime-workspace"'
      expect(@relative_url_regex).to_not match 'href="/another-project.sublime-workspace"'
      expect(@relative_url_regex).to_not match 'href="/menu.pdf"'
      expect(@relative_url_regex).to_not match 'href="https://untra.github.io"'

      # These should still match because they don't match the glob pattern
      expect(@relative_url_regex).to match 'href="/about/"'
      expect(@relative_url_regex).to match 'href="/contact/"'
    end

    it 'must not match excluded urls with glob patterns and baseurl' do
      # Test with glob pattern in exclude_from_localization and baseurl
      @site.config['exclude_from_localization'] = ['*.sublime-workspace']
      @site.prepare
      @site.exclude += @site.exclude_from_localization

      @baseurls.each do |baseurl|
        @site.baseurl = baseurl
        @relative_url_regex = @site.relative_url_regex

        # These should NOT match because they match the glob pattern
        expect(@relative_url_regex).to_not match "href=\"#{baseurl}/my-project.sublime-workspace\""
        expect(@relative_url_regex).to_not match "href=\"#{baseurl}/another-project.sublime-workspace\""

        # These should still match because they don't match the glob pattern
        expect(@relative_url_regex).to match "href=\"#{baseurl}/about/\""
        expect(@relative_url_regex).to match "href=\"#{baseurl}/contact/\""
      end
    end

    it 'disabled relativization must match ferh relative url with baseurl' do
      @baseurls.each do |baseurl|
        @site.baseurl = baseurl
        @urls.each do |url|
          @site.config['url'] = url
          @relative_url_regex = @site.relative_url_regex(true)
          expect(@relative_url_regex).to match "ferh=\"#{baseurl}/about/\""
          expect(@relative_url_regex).to match "ferh=\"#{baseurl}/about-the-product/\""
          expect(@relative_url_regex).to match "ferh=\"#{baseurl}/2016/all-new-flavors/\""
          expect(@relative_url_regex).to match "ferh=\"#{baseurl}/words-1-with-2-numbers-34/\""
          expect(@relative_url_regex).to match "ferh=\"#{baseurl}/\""
          expect(@relative_url_regex).to match "ferh=\"#{baseurl}/purchase/product/1234-business\""
          expect(@relative_url_regex).to match "ferh=\"#{baseurl}/#about\""
          expect(@relative_url_regex).to match "ferh=\"#{baseurl}/about/#team\""
        end
      end
    end
  end

  describe @derive_lang_from_path do
    before(:each) do
      config = Jekyll.configuration(
        'site' => @site,
        'languages'                 => ['en', 'es', 'pt-br'], # fr not included
        'default_lang'              => @default_lang,
        'exclude_from_localization' => @exclude_from_localization,
        'source'                    => File.expand_path('fixtures', __dir__),
        'lang_from_path'            => true
      )
      @site = Site.new(config)
      @site.prepare
    end
    it 'should derive lang from any part of the path' do
      collection_en = Jekyll::Collection.new(@site, 'en')
      collection_es = Jekyll::Collection.new(@site, 'es')
      collection_pt_br = Jekyll::Collection.new(@site, 'pt-br')
      collection_wrong = Jekyll::Collection.new(@site, 'wrong')
      specs = {
        'en' => [
          Jekyll::Document.new('about.en.md', site: @site, collection: collection_en),
          Jekyll::Document.new('fr/about.en.md', site: @site, collection: collection_en)
        ],
        'es' => [
          Jekyll::Document.new('pages/es/acercade.es.md', site: @site, collection: collection_es),
          Jekyll::Document.new('french-touch/restaurant/fr/es/acerade.md', site: @site, collection: collection_es)
        ],
        'pt-br' => [
          Jekyll::Document.new('about.pt-br.md', site: @site, collection: collection_pt_br),
          Jekyll::Document.new('international/restaurant/pt-br/sobre.md', site: @site, collection: collection_pt_br),
          # With case-insensitive matching, pt-BR in path should match pt-br in config
          Jekyll::Document.new('missing/pt-BR/sobre.md', site: @site, collection: collection_pt_br)
        ],
        nil => [
          Jekyll::Document.new('apropos.fr.md', site: @site, collection: collection_wrong), # not included in languages
          Jekyll::Document.new('taken/blues/newspaper.md', site: @site, collection: collection_wrong), # no matches
          Jekyll::Document.new('es-en-pt-br/wordswordswords.html', site: @site, collection: collection_wrong) # wont split
        ]
      }
      specs.each do |lang, docs|
        docs.each do |document|
          expect(@site.lang_from_path).to eq(true)
          derived = @site.derive_lang_from_path document
          if lang.nil?
            expect(derived).to be_nil
          else
            expect(derived).to eq(lang)
          end
        end
      end
    end
  end

  describe @absolute_url_regex do
    it 'must match absolute url' do
      @urls.each do |url|
        @site.config['url'] = url
        @site.prepare
        @absolute_url_regex = @site.absolute_url_regex(url)
        expect(@absolute_url_regex).to match "href=\"#{url}/javascript/65487-app.js\""
        expect(@absolute_url_regex).to match "href=\"#{url}/images/my-vacation-photo.jpg\""
        expect(@absolute_url_regex).to match "href=\"#{url}/css/stylesheet.css\""
      end
    end

    it 'must match absolute url' do
      @urls.each do |url|
        @site.config['url'] = url
        @absolute_url_regex = @site.absolute_url_regex(url)
        expect(@absolute_url_regex).to match "href=\"#{url}/javascript/65487-app.js\""
        expect(@absolute_url_regex).to match "href=\"#{url}/images/my-vacation-photo.jpg\""
        expect(@absolute_url_regex).to match "href=\"#{url}/css/stylesheet.css\""
      end
    end

    it 'must not match absolute url for another project' do
      @urls.each do |url|
        @site.config['url'] = url
        @absolute_url_regex = @site.absolute_url_regex(url)
        expect(@absolute_url_regex).to_not match 'href="http://test_github.io/javascript/65487-app.js'
        expect(@absolute_url_regex).to_not match 'href="http://test_github.io/images/my-vacation-photo.jpg'
        expect(@absolute_url_regex).to_not match 'href="http://github.io/css/stylesheet.css'
      end
    end

    it 'must not match whitespaced urls' do
      @urls.each do |url|
        @site.config['url'] = url
        @absolute_url_regex = @site.absolute_url_regex(url)
        expect(@absolute_url_regex).to_not match "href=\" #{url}/javascript/65487-app.js\""
        expect(@absolute_url_regex).to_not match "href=\" #{url}/images/my-vacation-photo.jpg\""
        expect(@absolute_url_regex).to_not match "href=\" #{url}/css/stylesheet.css\" "
      end
    end

    it 'must match absolute url with baseurl' do
      @baseurls.each do |baseurl|
        @site.baseurl = baseurl
        @urls.each do |url|
          @site.config['url'] = url
          @absolute_url_regex = @site.absolute_url_regex(url)
          expect(@absolute_url_regex).to match " href=\"#{url}#{baseurl}/javascript/65487-app.js\""
          expect(@absolute_url_regex).to match " href=\"#{url}#{baseurl}/images/my-vacation-photo.jpg\""
          expect(@absolute_url_regex).to match " href=\"#{url}#{baseurl}/css/stylesheet.css\""
        end
      end
    end

    it 'disabled relativization must match ferh absolute url with baseurl' do
      @baseurls.each do |baseurl|
        @site.baseurl = baseurl
        @urls.each do |url|
          @site.config['url'] = url
          @absolute_url_regex = @site.absolute_url_regex(url, true)
          expect(@absolute_url_regex).to match "ferh=\"#{url}#{baseurl}/javascript/65487-app.js\""
          expect(@absolute_url_regex).to match "ferh=\"#{url}#{baseurl}/images/my-vacation-photo.jpg\""
          expect(@absolute_url_regex).to match "ferh=\"#{url}#{baseurl}/css/stylesheet.css\""
        end
      end
    end

    it 'negative lookbehind for hreflang excludes default lang and x-default but not canonical' do
      @baseurls.each do |baseurl|
        @site.baseurl = baseurl
        @urls.each do |url|
          @site.config['url'] = url
          @absolute_url_regex = @site.absolute_url_regex(url)
          # Canonical URLs SHOULD be matched so they get language prefix on translated pages
          expect(@absolute_url_regex).to match "<link rel=\"canonical\" href=\"#{url}#{baseurl}/images/my-vacation-photo.jpg\">"
          # hreflang for default lang and x-default should NOT be matched
          expect(@absolute_url_regex).to_not match "<link rel=\"alternate\" hreflang=\"#{@default_lang}\" href=\"#{url}#{baseurl}/images/my-vacation-photo.jpg\">"
          # hreflang for non-default languages should be matched (they need relativization)
          expect(@absolute_url_regex).to match "<link rel=\"alternate\" hreflang=\"fr\" href=\"#{url}#{baseurl}/images/my-vacation-photo.jpg\">"
        end
      end
    end
  end

  describe 'site prepare' do
    it 'should copy active_lang to additional variables' do
      @site.config['lang_vars'] = ['locale', 'язык']
      @site.prepare
      @langs.each do |lang|
        @site.active_lang = lang
        expect(@site.site_payload['site']['locale']).to match lang
        expect(@site.site_payload['site']['язык']).to match lang
      end
    end
  end

  describe 'case-insensitive language matching' do
    before do
      @site_with_ptbr = Site.new(
        Jekyll.configuration(
          'languages'                 => ['en', 'pt-BR', 'zh-CN'],
          'default_lang'              => 'en',
          'source'                    => File.expand_path('fixtures', __dir__),
          'url'                       => 'https://test.github.io'
        )
      )
      @site_with_ptbr.prepare
    end

    it 'derive_lang_from_path matches language codes case-insensitively' do
      @site_with_ptbr.config['lang_from_path'] = true
      @site_with_ptbr.prepare

      collection = Jekyll::Collection.new(@site_with_ptbr, 'pages')
      doc_lower = Jekyll::Document.new('pages/pt-br/about.md', site: @site_with_ptbr, collection: collection)
      doc_upper = Jekyll::Document.new('pages/PT-BR/about.md', site: @site_with_ptbr, collection: collection)
      doc_mixed = Jekyll::Document.new('pages/Pt-Br/about.md', site: @site_with_ptbr, collection: collection)

      expect(@site_with_ptbr.derive_lang_from_path(doc_lower)).to eq('pt-BR')
      expect(@site_with_ptbr.derive_lang_from_path(doc_upper)).to eq('pt-BR')
      expect(@site_with_ptbr.derive_lang_from_path(doc_mixed)).to eq('pt-BR')
    end

    it 'coordinate_documents normalizes doc lang to config case' do
      collection = Jekyll::Collection.new(@site_with_ptbr, 'pages')
      doc = Jekyll::Document.new('test.md', site: @site_with_ptbr, collection: collection)
      doc.data['lang'] = 'pt-br'
      doc.data['permalink'] = '/test/'

      @site_with_ptbr.file_langs = {}
      @site_with_ptbr.active_lang = 'pt-BR'
      coordinated = @site_with_ptbr.coordinate_documents([doc])

      expect(coordinated).not_to be_empty
      expect(coordinated.first.data['lang']).to eq('pt-BR')
    end
  end

  describe @site do
    it 'should spawn no more than Etc.nprocessors processes' do
      forks = 0
      allow(Etc).to receive(:nprocessors).and_return(2)
      allow(@site).to receive(:fork) {
                        forks += 1
                        fork { sleep 2 }
                      }
      thr = Thread.new {
        sleep 1
        forks
      }
      @site.process
      expect(thr.value).to eq(Etc.nprocessors)
      expect(forks).to eq((@langs + [@default_lang]).uniq.length)
    end

    describe 'assignPageRedirects' do
      before do
        @collection = Jekyll::Collection.new(@site, 'test')
      end

      it 'should create redirects between all language versions' do
        # Create documents for different languages with the same page_id
        docs = [
          # English (default) version
          Jekyll::Document.new('test.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['page_id'] = 'test-page'
            doc.data['permalink'] = '/a-really-long/permalink/'
          end,
          # Chinese version
          Jekyll::Document.new('test.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'zh-CN'
            doc.data['page_id'] = 'test-page'
            doc.data['permalink'] = '/zh-CN/yi-tiao-chao-chang-de-yong-jiu-lian-jie/permalink/'
          end,
          # French version
          Jekyll::Document.new('test.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'fr'
            doc.data['page_id'] = 'test-page'
            doc.data['permalink'] = '/fr/un-tres-long/permalink/'
          end
        ]

        # Test redirects for each document
        docs.each do |doc|
          @site.assignPageRedirects(doc, docs)
          # Each document should have redirects from all other documents
          other_permalinks = docs.reject { |d| d.data['permalink'] == doc.data['permalink'] }
            .map { |d| d.data['permalink'] }
          expect(doc.data['redirect_from']).to match_array(other_permalinks)
        end
      end

      it 'should handle documents with lang-exclusive setting' do
        # Create documents with lang-exclusive setting
        docs = [
          # English version
          Jekyll::Document.new('test.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['page_id'] = 'test-page'
            doc.data['permalink'] = '/a-really-long/permalink/'
          end,
          # Chinese version with lang-exclusive
          Jekyll::Document.new('test.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'zh-CN'
            doc.data['page_id'] = 'test-page'
            doc.data['permalink'] = '/zh-CN/yi-tiao-chao-chang-de-yong-jiu-lian-jie/permalink/'
            doc.data['lang-exclusive'] = ['zh-CN']
          end
        ]

        # Test redirects for Chinese document
        @site.assignPageRedirects(docs[1], docs)
        expect(docs[1].data['redirect_from']).to include('/a-really-long/permalink/')
      end

      it 'should handle documents without page_id' do
        # Create a document without page_id
        doc = Jekyll::Document.new('test.md', site: @site, collection: @collection)
        doc.data['lang'] = 'en'
        doc.data['permalink'] = '/a-really-long/permalink/'

        # Should not raise error and should not set redirect_from
        expect { @site.assignPageRedirects(doc, [doc]) }.not_to raise_error
        expect(doc.data['redirect_from']).to be_nil
      end

      it 'should handle documents with derived language from path' do
        # Create documents with language derived from path
        docs = [
          # English version
          Jekyll::Document.new('test.md', site: @site, collection: @collection).tap do |doc|
            doc.data['page_id'] = 'test-page'
            doc.data['permalink'] = '/a-really-long/permalink/'
          end,
          # Chinese version with language in path
          Jekyll::Document.new('zh-CN/test.md', site: @site, collection: @collection).tap do |doc|
            doc.data['page_id'] = 'test-page'
            doc.data['permalink'] = '/zh-CN/yi-tiao-chao-chang-de-yong-jiu-lian-jie/permalink/'
          end
        ]

        # Enable lang_from_path
        @site.config['lang_from_path'] = true

        # Test redirects for Chinese document
        @site.assignPageRedirects(docs[1], docs)
        expect(docs[1].data['redirect_from']).to include('/a-really-long/permalink/')
      end

      # Tests for user-defined redirect_from handling
      it 'preserves user-defined redirect_from when page_id is not set' do
        doc = Jekyll::Document.new('test.md', site: @site, collection: @collection).tap do |d|
          d.data['lang'] = 'en'
          d.data['permalink'] = '/new-url/'
          d.data['redirect_from'] = ['/old-url/']
        end

        @site.assignPageRedirects(doc, [doc])

        expect(doc.data['redirect_from']).to eq(['/old-url/'])
      end

      it 'handles string redirect_from value' do
        doc = Jekyll::Document.new('test.md', site: @site, collection: @collection).tap do |d|
          d.data['lang'] = 'de'
          d.data['permalink'] = '/de/new-url/'
          d.data['redirect_from'] = '/old-url/' # String, not array
        end

        @site.assignPageRedirects(doc, [doc])

        expect(doc.data['redirect_from']).to be_a(Array)
      end

      it 'should preserve user-defined redirect_from when page_id is set' do
        doc = Jekyll::Document.new('test.md', site: @site, collection: @collection).tap do |d|
          d.data['lang'] = 'en'
          d.data['page_id'] = 'test-page'
          d.data['permalink'] = '/new-url/'
          d.data['redirect_from'] = ['/old-url/', '/legacy/']
        end

        other_doc = Jekyll::Document.new('test.de.md', site: @site, collection: @collection).tap do |d|
          d.data['lang'] = 'de'
          d.data['page_id'] = 'test-page'
          d.data['permalink'] = '/de/neue-url/'
        end

        @site.assignPageRedirects(doc, [doc, other_doc])

        expect(doc.data['redirect_from']).to include('/old-url/')
        expect(doc.data['redirect_from']).to include('/legacy/')
        expect(doc.data['redirect_from']).to include('/de/neue-url/')
      end

      it 'should scope user-defined redirect_from to document language for non-default languages' do
        doc = Jekyll::Document.new('test.de.md', site: @site, collection: @collection).tap do |d|
          d.data['lang'] = 'de'
          d.data['permalink'] = '/de/neue-url/'
          d.data['redirect_from'] = ['/alte-url/', '/legacy/']
        end

        @site.assignPageRedirects(doc, [doc])

        expect(doc.data['redirect_from']).to include('/de/alte-url/')
        expect(doc.data['redirect_from']).to include('/de/legacy/')
        expect(doc.data['redirect_from']).not_to include('/alte-url/')
      end

      it 'should not prefix redirect_from for default language' do
        doc = Jekyll::Document.new('test.md', site: @site, collection: @collection).tap do |d|
          d.data['lang'] = 'en'
          d.data['permalink'] = '/new-url/'
          d.data['redirect_from'] = ['/old-url/']
        end

        @site.assignPageRedirects(doc, [doc])

        expect(doc.data['redirect_from']).to eq(['/old-url/'])
      end

      it 'should not double-prefix redirects that already have language prefix' do
        doc = Jekyll::Document.new('test.de.md', site: @site, collection: @collection).tap do |d|
          d.data['lang'] = 'de'
          d.data['permalink'] = '/de/neue-url/'
          d.data['redirect_from'] = ['/de/alte-url/', '/legacy/']
        end

        @site.assignPageRedirects(doc, [doc])

        expect(doc.data['redirect_from']).to include('/de/alte-url/')
        expect(doc.data['redirect_from']).to include('/de/legacy/')
        expect(doc.data['redirect_from']).not_to include('/de/de/alte-url/')
      end
    end

    it 'parses static_href block and outputs correct HTML' do
      @site.active_lang = 'en'
      template = <<~LIQUID
        <link rel="alternate" hreflang="x-default" {% static_href %}href="https://test.github.io/"{% endstatic_href %} />
        <link rel="alternate" hreflang="en" {% static_href %}href="https://test.github.io/"{% endstatic_href %} />
        <link rel="alternate" hreflang="de" {% static_href %}href="https://test.github.io/de"{% endstatic_href %} />
        <link rel="alternate" hreflang="es" {% static_href %}href="https://test.github.io/es"{% endstatic_href %} />
        <link rel="alternate" hreflang="pt-BR" {% static_href %}href="https://test.github.io/pt-BR"{% endstatic_href %} />
      LIQUID
      expected = <<~HTML
        <link rel="alternate" hreflang="x-default" href="https://test.github.io/" />
        <link rel="alternate" hreflang="en" href="https://test.github.io/" />
        <link rel="alternate" hreflang="de" href="https://test.github.io/de" />
        <link rel="alternate" hreflang="es" href="https://test.github.io/es" />
        <link rel="alternate" hreflang="pt-BR" href="https://test.github.io/pt-BR" />
      HTML
      output = @site.liquid_renderer.file("").parse(template).render!(@site.site_payload, registers: { site: @site })
      url = 'https://test.github.io'
      non_abs_regex = @site.absolute_url_regex(url, true)
      file = Tempfile.new(['test', '.md'])
      file.write(output)
      file.rewind
      collection = Jekyll::Collection.new(@site, 'test')
      document = Jekyll::Document.new('test.md', site: @site, collection: collection).tap do |doc|
        doc.data['lang'] = 'en'
        doc.data['page_id'] = 'test-page'
        doc.data['permalink'] = '/a-really-long/permalink/'
        doc.output = output
      end
      corrected = @site.correct_nonrelativized_absolute_urls(document, non_abs_regex, url)
      if corrected != expected
        puts "output: #{output}"
        puts "expected: #{expected}"
        puts "corrected: #{corrected}"
      end
      expect(corrected.gsub(/\s+/, " ").strip).to eq(expected.gsub(/\s+/, " ").strip)
    end

    it 'parses static_href page_id associated hrefs correctly' do
      # Set up the documents with the provided frontmatters
      docs = [
        {
          lang: 'en',
          permalink: '/a-really-long/permalink/',
          title: 'A really long permalink',
          description: 'this page demonstrates'
        },
        {
          lang: 'pt-BR',
          permalink: '/um-longo/permalink/',
          title: 'Um permalink bem longo',
          description: 'esta página demonstra'
        },
        {
          lang: 'nl',
          permalink: '/een-hele-lange/permalink/',
          title: 'Een werkelijk lange permalink',
          description: 'deze pagina demonstreert'
        },
        {
          lang: 'zh-CN',
          permalink: '/yi-tiao-chao-chang-de-yong-jiu-lian-jie/permalink/',
          title: '一条超长的永久链接',
          description: '本页面演示了如何使用'
        }
      ]

      collection = Jekyll::Collection.new(@site, 'test')
      documents = docs.map do |attrs|
        Jekyll::Document.new('test.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = attrs[:title]
          doc.data['permalink'] = attrs[:permalink]
          doc.data['lang'] = attrs[:lang]
          doc.data['page_id'] = 'complex-permalink'
          doc.data['description'] = attrs[:description]
        end
      end

      url = 'https://test.github.io'

      # Simulate the template that outputs alternate links for each doc
      template = <<~LIQUID
        {% for doc in docs %}
        <link rel="alternate" hreflang="{{ doc.lang }}" {% static_href %}href="https://test.github.io{{ doc.permalink }}"{% endstatic_href %} />
        {% endfor %}
      LIQUID

      # Render the template with the documents as context
      payload = @site.site_payload.merge('docs' => documents.map(&:data))
      output = @site.liquid_renderer.file("").parse(template).render!(payload, registers: { site: @site })

      non_abs_regex = @site.absolute_url_regex(url, true)

      # For each document, run correct_nonrelativized_absolute_urls
      documents.each do |doc|
        doc.output = output
        @site.correct_nonrelativized_absolute_urls(doc, non_abs_regex, url)
      end

      # Build the expected HTML
      expected = docs.map do |attrs|
        %{<link rel="alternate" hreflang="#{attrs[:lang]}" href="#{url}#{attrs[:permalink]}" />}
      end.join("\n")

      # Compare the output of the first document (all docs have the same output)
      corrected_output = documents.first.output
      expect(corrected_output.gsub(/\s+/, " ").strip).to eq(expected.gsub(/\s+/, " ").strip)
    end

    it 'i18n_headers defaults custom permalink urls with site baseurl' do
      # Set up site config with baseurl
      @site.config['baseurl'] = '/mysite'
      @site.config['url'] = 'https://test.github.io'
      @site.prepare

      # Create a document with a page_id and custom permalinks for two languages
      collection = Jekyll::Collection.new(@site, 'test')
      docs = [
        Jekyll::Document.new('test.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'A really long permalink'
          doc.data['permalink'] = '/a-really-long/permalink/'
          doc.data['lang'] = 'en'
          doc.data['page_id'] = 'complex-permalink'
        end,
        Jekyll::Document.new('test.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'Een werkelijk lange permalink'
          doc.data['permalink'] = 'een-hele-lange/permalink/'
          doc.data['lang'] = 'de'
          doc.data['page_id'] = 'complex-permalink'
        end
      ]
      # Add the collection to the site!
      @site.collections['test'] = collection
      # Add the docs to the collection
      collection.docs.concat(docs)

      # Simulate a page context for the English doc
      page = docs[0].data.merge('permalink' => docs[0].data['permalink'], 'page_id' => docs[0].data['page_id'])
      context = Liquid::Context.new({}, {}, { site: @site, page: page })
      template = "{% i18n_headers %}"
      output = Liquid::Template.parse(template).render(context)

      # Expect the baseurl to be present in the hrefs
      expect(output).to include('href="https://test.github.io/mysite/a-really-long/permalink/"')
      expect(output).to include('href="https://test.github.io/mysite/de/een-hele-lange/permalink/"')
    end

    it 'i18n_headers uses the default_lang permalink for the default_lang alternate link' do
      @site.config['baseurl'] = '/mysite'
      @site.config['url'] = 'https://test.github.io'
      @site.config['languages'] = ['en', 'de']
      @site.config['default_lang'] = 'en'
      @site.prepare

      collection = Jekyll::Collection.new(@site, 'test')
      docs = [
        Jekyll::Document.new('test.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'A really long permalink'
          doc.data['permalink'] = '/a-really-long/permalink/'
          doc.data['lang'] = 'en'
          doc.data['page_id'] = 'complex-permalink'
        end,
        Jekyll::Document.new('test.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'Eine wirklich lange permalink'
          doc.data['permalink'] = '/de/eine-wirklich-lange/permalink/'
          doc.data['lang'] = 'de'
          doc.data['page_id'] = 'complex-permalink'
        end
      ]
      @site.collections['test'] = collection
      collection.docs.concat(docs)

      # Simulate a page context for the English doc
      page = docs[0].data.merge('permalink' => docs[0].data['permalink'], 'page_id' => docs[0].data['page_id'])
      context = Liquid::Context.new({}, {}, { site: @site, page: page })
      template = "{% i18n_headers %}"
      output = Liquid::Template.parse(template).render(context)

      # The default_lang alternate link should use the en permalink
      expect(output).to include('rel="alternate" hreflang="en" href="https://test.github.io/mysite/a-really-long/permalink/"')
      # The de alternate link should use the de permalink
      expect(output).to include('rel="alternate" hreflang="de" href="https://test.github.io/mysite/de/eine-wirklich-lange/permalink/"')
    end

    it 'i18n_headers outputs a canonical link for every language page' do
      @site.config['baseurl'] = ''
      @site.config['url'] = 'https://test.github.io'
      @site.config['languages'] = ['en', 'es', 'fr', 'de', 'sp']
      @site.config['default_lang'] = 'en'
      @site.prepare

      # Define permalinks for each language (some intentionally minimal for edge case)
      permalinks = {
        'en' => '/foo/bar/baz/',
        'es' => '/es/foo/bar/baz/',
        'fr' => '/fr/foo/bar/baz/'
      }

      collection = Jekyll::Collection.new(@site, 'test')
      docs = @site.config['languages'].map do |lang|
        Jekyll::Document.new('test.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = "A page in #{lang}"
          doc.data['permalink'] = permalinks[lang]
          doc.data['lang'] = lang
          doc.data['page_id'] = 'foo-bar-baz'
        end
      end
      @site.collections['test'] = collection
      collection.docs.concat(docs)

      # For each language, simulate the page context and check canonical
      @site.config['languages'].each do |lang|
        @site.active_lang = lang
        page = docs.find { |d| d.data['lang'] == lang }.data.merge('permalink' => permalinks[lang], 'page_id' => 'foo-bar-baz')
        context = Liquid::Context.new({}, {}, { site: @site, page: page })
        template = "{% i18n_headers %}"
        output = Liquid::Template.parse(template).render(context)
        # Check that a canonical link is present and not empty
        expect(output).to match(%r{<link rel="canonical" href="https://test\.github\.io[^"]*"\s*/>})
      end
    end

    it 'i18n_headers x-default hreflang points to default language version' do
      @site.config['baseurl'] = ''
      @site.config['url'] = 'https://www.example.com'
      @site.config['languages'] = ['en', 'de', 'es', 'pt-BR']
      @site.config['default_lang'] = 'en'
      @site.prepare

      # Create documents with different permalinks for each language
      collection = Jekyll::Collection.new(@site, 'test')
      docs = [
        Jekyll::Document.new('accessibility.en.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'Accessibility'
          doc.data['permalink'] = '/accessibility'
          doc.data['lang'] = 'en'
          doc.data['page_id'] = 'accessibility'
        end,
        Jekyll::Document.new('accessibility.de.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'Barrierefreiheit'
          doc.data['permalink'] = '/de/accessibility'
          doc.data['lang'] = 'de'
          doc.data['page_id'] = 'accessibility'
        end,
        Jekyll::Document.new('accessibility.es.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'Accesibilidad'
          doc.data['permalink'] = '/es/accessibility'
          doc.data['lang'] = 'es'
          doc.data['page_id'] = 'accessibility'
        end,
        Jekyll::Document.new('accessibility.pt-BR.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'Acessibilidade'
          doc.data['permalink'] = '/pt-BR/accessibility'
          doc.data['lang'] = 'pt-BR'
          doc.data['page_id'] = 'accessibility'
        end
      ]
      @site.collections['test'] = collection
      collection.docs.concat(docs)

      # Test from German page perspective
      @site.active_lang = 'de'
      page = docs.find { |d| d.data['lang'] == 'de' }.data.merge('page_id' => 'accessibility')
      context = Liquid::Context.new({}, {}, { site: @site, page: page })
      template = "{% i18n_headers %}"
      output = Liquid::Template.parse(template).render(context)

      # x-default should point to the English (default) version, not the German version
      expect(output).to include('hreflang="x-default" href="https://www.example.com/accessibility"')
      expect(output).to include('hreflang="en" href="https://www.example.com/accessibility"')
      expect(output).to include('hreflang="de" href="https://www.example.com/de/accessibility"')
      expect(output).to include('hreflang="es" href="https://www.example.com/es/accessibility"')
      expect(output).to include('hreflang="pt-BR" href="https://www.example.com/pt-BR/accessibility"')
      expect(output).to_not include('hreflang="en" ferh="https://www.example.com/accessibility"')
    end

    it 'i18n_headers x-default always points to default language regardless of current page language' do
      @site.config['baseurl'] = ''
      @site.config['url'] = 'https://www.discourse.org'
      @site.config['languages'] = ['en', 'de', 'es', 'pt-BR']
      @site.config['default_lang'] = 'en'
      @site.prepare

      # Create documents with different permalinks for each language
      collection = Jekyll::Collection.new(@site, 'test')
      docs = [
        Jekyll::Document.new('accessibility.en.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'Accessibility'
          doc.data['permalink'] = '/accessibility'
          doc.data['lang'] = 'en'
          doc.data['page_id'] = 'accessibility'
        end,
        Jekyll::Document.new('accessibility.de.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'Barrierefreiheit'
          doc.data['permalink'] = '/de/accessibility'
          doc.data['lang'] = 'de'
          doc.data['page_id'] = 'accessibility'
        end,
        Jekyll::Document.new('accessibility.es.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'Accesibilidad'
          doc.data['permalink'] = '/es/accessibility'
          doc.data['lang'] = 'es'
          doc.data['page_id'] = 'accessibility'
        end,
        Jekyll::Document.new('accessibility.pt-BR.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'Acessibilidade'
          doc.data['permalink'] = '/pt-BR/accessibility'
          doc.data['lang'] = 'pt-BR'
          doc.data['page_id'] = 'accessibility'
        end
      ]
      @site.collections['test'] = collection
      collection.docs.concat(docs)

      # Test from each language page perspective
      ['en', 'de', 'es', 'pt-BR'].each do |current_lang|
        @site.active_lang = current_lang
        page = docs.find { |d| d.data['lang'] == current_lang }.data.merge('page_id' => 'accessibility')
        context = Liquid::Context.new({}, {}, { site: @site, page: page })
        template = "{% i18n_headers %}"
        output = Liquid::Template.parse(template).render(context)

        # x-default should ALWAYS point to the English (default) version, regardless of current language
        expect(output).to include('hreflang="x-default" href="https://www.discourse.org/accessibility"')

        # The canonical should point to the current language version
        if current_lang == 'en'
          expect(output).to include('rel="canonical" href="https://www.discourse.org/accessibility"')
        else
          expect(output).to include("rel=\"canonical\" href=\"https://www.discourse.org/#{current_lang}/accessibility\"")
        end
      end
    end

    it 'i18n_headers works with posts that have translations via page_id' do
      @site.config['baseurl'] = ''
      @site.config['url'] = 'https://test.github.io'
      @site.config['languages'] = ['en', 'fr']
      @site.config['default_lang'] = 'en'
      @site.prepare

      # Simulate two posts in different languages with same page_id
      post_date = Time.new(2024, 6, 1)
      collection = Jekyll::Collection.new(@site, 'posts')
      inferred_permalink = "/2024/06/01/my-inferred-post/"
      posts = [
        Jekyll::Document.new('2024-06-01-my-inferred-post.en.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'post'
          doc.data['title'] = 'My Inferred Post'
          doc.data['lang'] = 'en'
          doc.data['page_id'] = 'my-inferred-post'
          doc.data['permalink'] = inferred_permalink
          doc.data['date'] = post_date
          doc.data['url'] = inferred_permalink
        end,
        Jekyll::Document.new('2024-06-01-my-inferred-post.fr.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'post'
          doc.data['title'] = 'Mon Article Inféré'
          doc.data['lang'] = 'fr'
          doc.data['page_id'] = 'my-inferred-post'
          doc.data['permalink'] = inferred_permalink
          doc.data['date'] = post_date
          doc.data['url'] = inferred_permalink
        end
      ]
      @site.collections['posts'] = collection
      collection.docs.concat(posts)

      # Simulate the page context for the English post
      page = posts[0].data.merge('page_id' => 'my-inferred-post')
      context = Liquid::Context.new({}, {}, { site: @site, page: page })
      template = "{% i18n_headers %}"
      output = Liquid::Template.parse(template).render(context)

      # Canonical should be for the current language
      expect(output).to include(%{<link rel="canonical" href="https://test.github.io#{inferred_permalink}"/>})
      # Alternate for English (default)
      expect(output).to include(%{<link rel="alternate" hreflang="en" href="https://test.github.io#{inferred_permalink}"/>})
      # Alternate for French (should be /fr/ prefix)
      expect(output).to include(%{<link rel="alternate" hreflang="fr" href="https://test.github.io/fr#{inferred_permalink}"/>})
    end

    it 'handles case-mismatched lang in frontmatter during coordinate_documents' do
      @site.config['baseurl'] = ''
      @site.config['url'] = 'https://test.github.io'
      @site.config['languages'] = ['en', 'pt-BR']
      @site.config['default_lang'] = 'en'
      @site.prepare

      collection = Jekyll::Collection.new(@site, 'pages')
      doc = Jekyll::Document.new('test.pt-br.md', site: @site, collection: collection)
      doc.data['lang'] = 'pt-br'
      doc.data['page_id'] = 'test-page'
      doc.data['permalink'] = '/test/'

      @site.file_langs = {}
      @site.active_lang = 'pt-BR'
      coordinated = @site.coordinate_documents([doc])

      expect(coordinated).not_to be_empty
      # Doc lang should be normalized to config case
      expect(coordinated.first.data['lang']).to eq('pt-BR')
    end

    it 'i18n_headers only generates hreflang for languages with actual translations' do
      @site.config['baseurl'] = ''
      @site.config['url'] = 'https://test.github.io'
      @site.config['languages'] = ['en', 'es', 'fr', 'de']
      @site.config['default_lang'] = 'en'
      @site.prepare

      # Create a page that only has English and Spanish translations (no French or German)
      collection = Jekyll::Collection.new(@site, 'test')
      docs = [
        Jekyll::Document.new('about.en.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'About Us'
          doc.data['permalink'] = '/about/'
          doc.data['lang'] = 'en'
          doc.data['page_id'] = 'about'
        end,
        Jekyll::Document.new('about.es.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'Sobre Nosotros'
          doc.data['permalink'] = '/es/sobre-nosotros/'
          doc.data['lang'] = 'es'
          doc.data['page_id'] = 'about'
        end
      ]
      @site.collections['test'] = collection
      collection.docs.concat(docs)

      # Simulate the page context for the English doc
      page = docs[0].data.merge('permalink' => '/about/', 'page_id' => 'about')
      context = Liquid::Context.new({}, {}, { site: @site, page: page })
      template = "{% i18n_headers %}"
      output = Liquid::Template.parse(template).render(context)

      # Should include hreflang for English (default language, always included)
      expect(output).to include('hreflang="en"')
      # Should include hreflang for Spanish (has translation)
      expect(output).to include('hreflang="es"')
      # Should NOT include hreflang for French (no translation)
      expect(output).to_not include('hreflang="fr"')
      # Should NOT include hreflang for German (no translation)
      expect(output).to_not include('hreflang="de"')
      # Should still include x-default
      expect(output).to include('hreflang="x-default"')
    end

    it 'i18n_headers detects translations in standalone pages (not just collections)' do
      @site.config['baseurl'] = ''
      @site.config['url'] = 'https://test.github.io'
      @site.config['languages'] = ['en', 'es', 'fr', 'de']
      @site.config['default_lang'] = 'en'
      @site.prepare

      # Create standalone pages (not in collections) with page_id - only English and Spanish translations
      # Using a TestPage Struct to simulate Jekyll::Page objects with data hash
      page_en = TestPage.new({
        'layout' => 'page',
        'title' => 'About Us',
        'permalink' => '/about/',
        'lang' => 'en',
        'page_id' => 'about-page'
      })
      page_es = TestPage.new({
        'layout' => 'page',
        'title' => 'Sobre Nosotros',
        'permalink' => '/es/sobre-nosotros/',
        'lang' => 'es',
        'page_id' => 'about-page'
      })

      # Add pages to site.pages (not to collections)
      @site.pages << page_en
      @site.pages << page_es

      # Simulate the page context for the English page
      page = page_en.data.merge('permalink' => '/about/', 'page_id' => 'about-page')
      context = Liquid::Context.new({}, {}, { site: @site, page: page })
      template = "{% i18n_headers %}"
      output = Liquid::Template.parse(template).render(context)

      # Should include hreflang for English (default language, always included)
      expect(output).to include('hreflang="en"')
      # Should include hreflang for Spanish (has translation via standalone page)
      expect(output).to include('hreflang="es"')
      # Should NOT include hreflang for French (no translation)
      expect(output).to_not include('hreflang="fr"')
      # Should NOT include hreflang for German (no translation)
      expect(output).to_not include('hreflang="de"')
      # Should still include x-default
      expect(output).to include('hreflang="x-default"')
    end

    it 'i18n_headers finds translations by matching permalink when no page_id is set' do
      @site.config['baseurl'] = ''
      @site.config['url'] = 'https://test.github.io'
      @site.config['languages'] = ['en', 'es', 'fr', 'de']
      @site.config['default_lang'] = 'en'
      @site.prepare

      # Create standalone pages with same permalink but NO page_id - only lang differs
      # This is a common pattern: same permalink, different lang frontmatter
      page_en = TestPage.new({
        'layout' => 'page',
        'title' => 'About Us',
        'permalink' => '/about/',
        'lang' => 'en'
        # No page_id!
      })
      page_es = TestPage.new({
        'layout' => 'page',
        'title' => 'Sobre Nosotros',
        'permalink' => '/about/', # Same permalink as English
        'lang' => 'es'
        # No page_id!
      })

      # Add pages to site.pages
      @site.pages << page_en
      @site.pages << page_es

      # Simulate the page context for the English page
      page = page_en.data.merge('permalink' => '/about/')
      context = Liquid::Context.new({}, {}, { site: @site, page: page })
      template = "{% i18n_headers %}"
      output = Liquid::Template.parse(template).render(context)

      # Should include hreflang for English (default language, always included)
      expect(output).to include('hreflang="en"')
      # Should include hreflang for Spanish (has translation via same permalink)
      expect(output).to include('hreflang="es"')
      # Should NOT include hreflang for French (no translation)
      expect(output).to_not include('hreflang="fr"')
      # Should NOT include hreflang for German (no translation)
      expect(output).to_not include('hreflang="de"')
      # Should still include x-default
      expect(output).to include('hreflang="x-default"')
    end

    it 'i18n_headers treats pages without lang frontmatter as default language' do
      @site.config['baseurl'] = ''
      @site.config['url'] = 'https://test.github.io'
      @site.config['languages'] = ['en', 'es', 'fr', 'de']
      @site.config['default_lang'] = 'en'
      @site.prepare

      # Create a single page WITHOUT lang frontmatter (common real-world case)
      # This page should only have English hreflang, not all languages
      page_no_lang = TestPage.new({
        'layout' => 'page',
        'title' => 'About Us',
        'permalink' => '/about/'
        # No lang! This is the key case
      })

      # Add page to site.pages
      @site.pages << page_no_lang

      # Simulate the page context
      page = page_no_lang.data.merge('permalink' => '/about/')
      context = Liquid::Context.new({}, {}, { site: @site, page: page })
      template = "{% i18n_headers %}"
      output = Liquid::Template.parse(template).render(context)

      # Should include hreflang for English (default language, page assumed to be English)
      expect(output).to include('hreflang="en"')
      # Should NOT include hreflang for Spanish (no translation)
      expect(output).to_not include('hreflang="es"')
      # Should NOT include hreflang for French (no translation)
      expect(output).to_not include('hreflang="fr"')
      # Should NOT include hreflang for German (no translation)
      expect(output).to_not include('hreflang="de"')
      # Should still include x-default
      expect(output).to include('hreflang="x-default"')
    end

    it 'absolute_url_regex matches canonical URLs for relativization' do
      @site.config['baseurl'] = ''
      @site.config['url'] = 'https://test.github.io'
      @site.config['languages'] = ['en', 'fr']
      @site.config['default_lang'] = 'en'
      @site.prepare

      url = 'https://test.github.io'
      @absolute_url_regex = @site.absolute_url_regex(url)

      # Canonical URLs SHOULD be matched so they get language prefix on translated pages
      expect(@absolute_url_regex).to match '<link rel="canonical" href="https://test.github.io/about">'
      # hreflang URLs should NOT be matched (they already have correct URLs)
      expect(@absolute_url_regex).to_not match '<link rel="alternate" hreflang="en" href="https://test.github.io/about">'
      expect(@absolute_url_regex).to_not match '<link rel="alternate" hreflang="x-default" href="https://test.github.io/about">'
    end

    it 'fallback_canonical_to_default_lang defaults to false' do
      @site.config['baseurl'] = ''
      @site.config['url'] = 'https://test.github.io'
      @site.config['languages'] = ['en', 'fr']
      @site.config['default_lang'] = 'en'
      @site.config.delete('fallback_canonical_to_default_lang')
      @site.prepare

      expect(@site.fallback_canonical_to_default_lang).to eq(false)
    end

    it 'i18n_headers canonical points to default lang for fallback pages when fallback_canonical_to_default_lang is true' do
      @site.config['baseurl'] = ''
      @site.config['url'] = 'https://test.github.io'
      @site.config['languages'] = ['en', 'es', 'fr']
      @site.config['default_lang'] = 'en'
      @site.config['fallback_canonical_to_default_lang'] = true
      @site.prepare

      # Create a page with only English translation (no Spanish or French)
      collection = Jekyll::Collection.new(@site, 'test')
      docs = [
        Jekyll::Document.new('about.en.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'About Us'
          doc.data['permalink'] = '/about/'
          doc.data['lang'] = 'en'
          doc.data['page_id'] = 'about'
        end
      ]
      @site.collections['test'] = collection
      collection.docs.concat(docs)

      # Test from Spanish page perspective (which is a fallback page)
      @site.active_lang = 'es'
      page = docs[0].data.merge('permalink' => '/about/', 'page_id' => 'about')
      context = Liquid::Context.new({}, {}, { site: @site, page: page })
      template = "{% i18n_headers %}"
      output = Liquid::Template.parse(template).render(context)

      # Canonical should point to the default language (English) URL, not Spanish
      expect(output).to include('rel="canonical" href="https://test.github.io/about/"')
      expect(output).to_not include('rel="canonical" href="https://test.github.io/es/about/"')
    end

    it 'i18n_headers canonical points to current lang for pages with actual translations even when fallback_canonical_to_default_lang is true' do
      @site.config['baseurl'] = ''
      @site.config['url'] = 'https://test.github.io'
      @site.config['languages'] = ['en', 'es', 'fr']
      @site.config['default_lang'] = 'en'
      @site.config['fallback_canonical_to_default_lang'] = true
      @site.prepare

      # Create a page with English AND Spanish translations
      collection = Jekyll::Collection.new(@site, 'test')
      docs = [
        Jekyll::Document.new('about.en.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'About Us'
          doc.data['permalink'] = '/about/'
          doc.data['lang'] = 'en'
          doc.data['page_id'] = 'about'
        end,
        Jekyll::Document.new('about.es.md', site: @site, collection: collection).tap do |doc|
          doc.data['layout'] = 'page'
          doc.data['title'] = 'Sobre Nosotros'
          doc.data['permalink'] = '/es/sobre-nosotros/'
          doc.data['lang'] = 'es'
          doc.data['page_id'] = 'about'
        end
      ]
      @site.collections['test'] = collection
      collection.docs.concat(docs)

      # Test from Spanish page perspective (which HAS a translation)
      @site.active_lang = 'es'
      page = docs[1].data.merge('permalink' => '/es/sobre-nosotros/', 'page_id' => 'about')
      context = Liquid::Context.new({}, {}, { site: @site, page: page })
      template = "{% i18n_headers %}"
      output = Liquid::Template.parse(template).render(context)

      # Canonical should point to the Spanish URL since it has a real translation
      expect(output).to include('rel="canonical" href="https://test.github.io/es/sobre-nosotros/"')
      expect(output).to_not include('rel="canonical" href="https://test.github.io/about/"')
    end

    describe 'rendered_lang' do
      before do
        @collection = Jekyll::Collection.new(@site, 'test')
      end

      it 'sets rendered_lang to explicit lang frontmatter value' do
        docs = [
          Jekyll::Document.new('about.en.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['page_id'] = 'about'
          end,
          Jekyll::Document.new('about.es.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'sp'
            doc.data['page_id'] = 'about'
          end
        ]

        @site.active_lang = 'en'
        @site.coordinate_documents(docs)

        # Each doc should have rendered_lang set to its explicit lang
        expect(docs[0].data['rendered_lang']).to eq('en')
        expect(docs[1].data['rendered_lang']).to eq('sp')
      end

      it 'sets rendered_lang to default_lang for pages without lang frontmatter' do
        doc = Jekyll::Document.new('about.md', site: @site, collection: @collection).tap do |d|
          d.data['page_id'] = 'about'
          # No lang set!
        end

        @site.active_lang = 'en'
        @site.coordinate_documents([doc])

        # Should fall back to default_lang
        expect(doc.data['rendered_lang']).to eq(@site.default_lang)
      end

      it 'allows templates to detect fallback pages by comparing rendered_lang to active_lang' do
        # Create a page with only English content
        doc = Jekyll::Document.new('about.md', site: @site, collection: @collection).tap do |d|
          d.data['lang'] = 'en'
          d.data['page_id'] = 'about'
        end

        # Process for English build
        @site.active_lang = 'en'
        @site.coordinate_documents([doc])
        expect(doc.data['rendered_lang']).to eq('en')
        # rendered_lang == active_lang means it's a real translation
        expect(doc.data['rendered_lang']).to eq(@site.active_lang)

        # Now simulate Spanish build (same doc, no Spanish translation exists)
        @site.active_lang = 'sp'
        # rendered_lang stays 'en' (the actual language of the content)
        # This allows templates to check: rendered_lang != active_lang means fallback
        expect(doc.data['rendered_lang']).to eq('en')
        expect(doc.data['rendered_lang']).to_not eq(@site.active_lang)
      end

      it 'sets rendered_lang based on lang_from_path when enabled' do
        # Enable lang_from_path
        @site.config['lang_from_path'] = true
        @site.config['languages'] = ['en', 'es', 'pt-br']
        @site.prepare

        collection = Jekyll::Collection.new(@site, 'test')
        doc = Jekyll::Document.new('pages/es/about.md', site: @site, collection: collection).tap do |d|
          d.data['page_id'] = 'about'
          # No explicit lang, should derive from path
        end

        @site.active_lang = 'en'
        @site.coordinate_documents([doc])

        # Should derive lang from path
        expect(doc.data['rendered_lang']).to eq('es')
      end
    end

    describe 'coordinate_documents with unconfigured languages' do
      before do
        @collection = Jekyll::Collection.new(@site, 'test')
      end

      it 'should exclude documents with unconfigured lang in frontmatter' do
        # Configure site with only en and es
        @site.config['languages'] = ['en', 'es']
        @site.config['default_lang'] = 'en'
        @site.prepare

        docs = [
          # lang: en - should be included
          Jekyll::Document.new('test-en.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['title'] = 'English Page'
          end,
          # lang: de - should be excluded (not in config)
          Jekyll::Document.new('test-de.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'de'
            doc.data['title'] = 'German Page'
          end,
          # lang: es - should be included
          Jekyll::Document.new('test-es.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'es'
            doc.data['title'] = 'Spanish Page'
          end
        ]

        coordinated = @site.coordinate_documents(docs)
        coordinated_langs = coordinated.map { |d| d.data['lang'] }

        expect(coordinated_langs).to include('en')
        expect(coordinated_langs).to include('es')
        expect(coordinated_langs).not_to include('de')
      end

      it 'should include documents with default_lang even if not in languages array' do
        # Configure with es and fr, but default_lang is en
        @site.config['languages'] = ['es', 'fr']
        @site.config['default_lang'] = 'en'
        @site.prepare

        docs = [
          # lang: en (default_lang) - should be included
          Jekyll::Document.new('test-en.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['title'] = 'English Page'
          end,
          # lang: es - should be included
          Jekyll::Document.new('test-es.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'es'
            doc.data['title'] = 'Spanish Page'
          end,
          # lang: de - should be excluded
          Jekyll::Document.new('test-de.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'de'
            doc.data['title'] = 'German Page'
          end
        ]

        coordinated = @site.coordinate_documents(docs)
        coordinated_langs = coordinated.map { |d| d.data['lang'] }

        expect(coordinated_langs).to include('en') # default_lang always included
        expect(coordinated_langs).to include('es')
        expect(coordinated_langs).not_to include('de')
      end

      it 'should log warning when excluding documents with unconfigured language' do
        @site.config['languages'] = ['en', 'es']
        @site.config['default_lang'] = 'en'
        @site.prepare

        doc = Jekyll::Document.new('test-de.md', site: @site, collection: @collection)
        doc.data['lang'] = 'de'
        doc.data['title'] = 'German Page'

        expect(Jekyll.logger).to receive(:warn).with("Polyglot:", /lang 'de' not in configured/)

        @site.coordinate_documents([doc])
      end

      it 'should not serve unconfigured language pages as default language content' do
        # Real-world scenario: site configured with limited languages for dev builds,
        # but pages exist for many languages from production config.
        # German pages should not appear when only en and pt-BR are configured.
        @site.config['languages'] = ['en', 'pt-BR']
        @site.config['default_lang'] = 'en'
        @site.prepare

        # Simulate Jekyll::Page objects using OpenStruct (like site.pages)
        pages = [
          TestPage.new({ 'lang' => 'en', 'page_id' => 'home', 'permalink' => '/',
                         'title' => 'The SQL Editor You Love' }, '/'),
          TestPage.new({ 'lang' => 'de', 'page_id' => 'home', 'permalink' => '/',
                         'title' => 'Der SQL-Editor Ihrer Träume' }, '/'),
          TestPage.new({ 'lang' => 'pt-BR', 'page_id' => 'home', 'permalink' => '/',
                         'title' => 'O Editor SQL dos Seus Sonhos' }, '/'),
          TestPage.new({ 'lang' => 'fr', 'page_id' => 'home', 'permalink' => '/',
                         'title' => "L'éditeur SQL de vos rêves" }, '/')
        ]

        # Building for default language (en)
        @site.active_lang = 'en'
        coordinated = @site.coordinate_documents(pages)

        # Only configured languages should appear
        coordinated_langs = coordinated.map { |p| p.data['lang'] }
        expect(coordinated_langs).not_to include('de')
        expect(coordinated_langs).not_to include('fr')

        # The winning page for the default language build should be English
        expect(coordinated.length).to eq(1)
        expect(coordinated[0].data['title']).to eq('The SQL Editor You Love')
      end

      it 'should filter by explicit frontmatter lang even if lang resolves to default' do
        # This test catches a bug where normalize_lang (on other branches) converts
        # unknown lang codes to nil, which then falls back to default_lang,
        # bypassing the valid_languages filter.
        # The filter must check the ORIGINAL frontmatter lang value, not the resolved one.
        @site.config['languages'] = ['en', 'pt-BR']
        @site.config['default_lang'] = 'en'
        @site.prepare

        collection = Jekyll::Collection.new(@site, 'test')
        docs = [
          Jekyll::Document.new('index.html', site: @site, collection: collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['page_id'] = 'home'
            doc.data['title'] = 'English Home'
          end,
          # This doc has explicit lang: de in frontmatter.
          # Even if a normalize step maps 'de' -> nil -> default_lang,
          # it should still be excluded because 'de' is not configured.
          Jekyll::Document.new('index-de.html', site: @site, collection: collection).tap do |doc|
            doc.data['lang'] = 'de'
            doc.data['page_id'] = 'home'
            doc.data['title'] = 'German Home'
          end
        ]

        @site.active_lang = 'en'
        coordinated = @site.coordinate_documents(docs)

        # The German doc must NOT be in the output
        titles = coordinated.map { |d| d.data['title'] }
        expect(titles).to include('English Home')
        expect(titles).not_to include('German Home')

        # Verify the German doc's explicit lang was the reason for exclusion
        coordinated_langs = coordinated.map { |d| d.data['lang'] }
        expect(coordinated_langs).not_to include('de')
      end
    end

    describe 'assignPageLanguagePermalinks with unconfigured languages' do
      before do
        @collection = Jekyll::Collection.new(@site, 'test')
      end

      it 'should only include configured languages in permalink_lang' do
        @site.config['languages'] = ['en', 'es']
        @site.config['default_lang'] = 'en'
        @site.prepare

        # Create docs with en, es, de (de not configured)
        docs = [
          Jekyll::Document.new('test-en.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['page_id'] = 'test-page'
            doc.data['permalink'] = '/test/'
          end,
          Jekyll::Document.new('test-es.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'es'
            doc.data['page_id'] = 'test-page'
            doc.data['permalink'] = '/es/test/'
          end,
          Jekyll::Document.new('test-de.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'de'
            doc.data['page_id'] = 'test-page'
            doc.data['permalink'] = '/de/test/'
          end
        ]

        # Call assignPageLanguagePermalinks on the English doc
        @site.assignPageLanguagePermalinks(docs[0], docs)

        # Verify permalink_lang only has keys for en and es
        expect(docs[0].data['permalink_lang'].keys).to include('en')
        expect(docs[0].data['permalink_lang'].keys).to include('es')
        expect(docs[0].data['permalink_lang'].keys).not_to include('de')
      end
    end

    describe '#find_translations' do
      before do
        @site.config['languages'] = ['en', 'es', 'de']
        @site.config['default_lang'] = 'en'
        @site.prepare
        @collection = Jekyll::Collection.new(@site, 'test')
      end

      it 'returns a hash of {lang => permalink} keyed by page_id' do
        docs = [
          Jekyll::Document.new('about-en.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/about/'
          end,
          Jekyll::Document.new('about-es.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'es'
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/es/about/'
          end,
          Jekyll::Document.new('about-de.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'de'
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/de/about/'
          end
        ]

        result = @site.find_translations('about', nil, docs)

        expect(result).to be_a(Hash)
        expect(result.keys).to contain_exactly('en', 'es', 'de')
        expect(result['en']).to eq('/about/')
        expect(result['es']).to eq('/es/about/')
        expect(result['de']).to eq('/de/about/')
      end

      it 'falls back to permalink-only matching when page_id is empty' do
        # Docs share NO page_id; matching must happen by normalized permalink.
        # This is the latent bug fix: prior code compared raw vs normalized and
        # would have missed the es/de docs whose permalinks carry a lang prefix.
        docs = [
          Jekyll::Document.new('about-en.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['permalink'] = '/about/'
          end,
          Jekyll::Document.new('about-es.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'es'
            doc.data['permalink'] = '/es/about/'
          end,
          Jekyll::Document.new('about-de.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'de'
            doc.data['permalink'] = '/de/about/'
          end
        ]

        result = @site.find_translations(nil, '/about/', docs)

        expect(result.keys).to contain_exactly('en', 'es', 'de')
        expect(result['es']).to eq('/es/about/')
        expect(result['de']).to eq('/de/about/')
      end

      it 'returns {} when both page_id and normalized_permalink are empty' do
        docs = [
          Jekyll::Document.new('about-en.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['permalink'] = '/about/'
          end
        ]

        expect(@site.find_translations(nil, nil, docs)).to eq({})
        expect(@site.find_translations('', '', docs)).to eq({})
      end

      it 'excludes docs whose explicit lang is not in the configured languages list' do
        docs = [
          Jekyll::Document.new('about-en.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/about/'
          end,
          Jekyll::Document.new('about-fr.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'fr' # fr is NOT in configured ['en','es','de']
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/fr/about/'
          end
        ]

        result = @site.find_translations('about', nil, docs)

        expect(result.keys).to include('en')
        expect(result.keys).not_to include('fr')
      end

      it 'treats nil page_id as empty (falls through to permalink path)' do
        # Regression guard against reverting to `if page_id` truthy check,
        # which would have entered the page_id select branch with `nil ==`.
        docs = [
          Jekyll::Document.new('about-en.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['permalink'] = '/about/'
          end
        ]

        result = @site.find_translations(nil, '/about/', docs)
        expect(result['en']).to eq('/about/')
      end

      it 'defaults candidate_docs to collections + pages when omitted' do
        doc = Jekyll::Document.new('about-en.md', site: @site, collection: @collection).tap do |d|
          d.data['lang'] = 'en'
          d.data['page_id'] = 'about'
          d.data['permalink'] = '/about/'
        end
        @site.collections['test'] = @collection
        @collection.docs.push(doc)

        page = TestPage.new({
          'lang' => 'es',
          'page_id' => 'about',
          'permalink' => '/es/about/'
        }, '/es/about/', 'about-es.md')
        @site.pages << page

        # Two-arg call (same shape Liquid's I18nHeadersTag uses)
        result = @site.find_translations('about', nil)

        expect(result.keys).to contain_exactly('en', 'es')
        expect(result['en']).to eq('/about/')
        expect(result['es']).to eq('/es/about/')
      end

      it 'applies derive_lang_from_path when lang_from_path is enabled and frontmatter lacks lang' do
        @site.config['lang_from_path'] = true
        @site.prepare # reload lang_from_path flag

        docs = [
          Jekyll::Document.new('en/about.md', site: @site, collection: @collection).tap do |doc|
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/about/'
            # no explicit lang frontmatter — must be derived from path segment
          end,
          Jekyll::Document.new('es/about.md', site: @site, collection: @collection).tap do |doc|
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/es/about/'
          end
        ]

        result = @site.find_translations('about', nil, docs)

        expect(result.keys).to include('es')
        expect(result['es']).to eq('/es/about/')
      end
    end

    describe '#normalized_permalink_for_doc' do
      before do
        @site.config['languages'] = ['en', 'de']
        @site.config['default_lang'] = 'en'
        @site.prepare
      end

      it 'returns nil when both data["permalink"] and url are empty' do
        page = TestPage.new({}, '', 'somewhere.md')
        expect(@site.normalized_permalink_for_doc(page)).to be_nil
      end

      it 'prefixes a leading slash when permalink lacks one' do
        page = TestPage.new({ 'permalink' => 'about/' }, nil, 'about.md')
        expect(@site.normalized_permalink_for_doc(page)).to eq('/about/')
      end

      it "strips the doc's own lang prefix" do
        page = TestPage.new({ 'lang' => 'de', 'permalink' => '/de/about/' }, nil, 'about.md')
        expect(@site.normalized_permalink_for_doc(page)).to eq('/about/')
      end

      it 'leaves permalink unchanged when data["lang"] is empty/nil' do
        without_lang = TestPage.new({ 'permalink' => '/about/' }, nil, 'about.md')
        empty_lang = TestPage.new({ 'lang' => '', 'permalink' => '/about/' }, nil, 'about.md')
        expect(@site.normalized_permalink_for_doc(without_lang)).to eq('/about/')
        expect(@site.normalized_permalink_for_doc(empty_lang)).to eq('/about/')
      end

      it 'falls back to doc.url when data["permalink"] is empty' do
        page = TestPage.new({ 'lang' => 'de' }, '/de/about/', 'about.md')
        expect(@site.normalized_permalink_for_doc(page)).to eq('/about/')
      end
    end

    describe 'assignPageLanguagePermalinks new keys and behavior changes' do
      before do
        @collection = Jekyll::Collection.new(@site, 'test')
      end

      it 'assigns available_languages matching permalink_lang.keys' do
        @site.config['languages'] = ['en', 'es', 'de']
        @site.config['default_lang'] = 'en'
        @site.prepare

        docs = [
          Jekyll::Document.new('about-en.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/about/'
          end,
          Jekyll::Document.new('about-es.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'es'
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/es/about/'
          end,
          Jekyll::Document.new('about-de.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'de'
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/de/about/'
          end
        ]

        @site.assignPageLanguagePermalinks(docs[0], docs)

        expect(docs[0].data['available_languages']).to match_array(docs[0].data['permalink_lang'].keys)
        expect(docs[0].data['available_languages']).to contain_exactly('en', 'es', 'de')
      end

      it 'assigns missing_languages for partially translated multi-lang pages' do
        @site.config['languages'] = ['en', 'es', 'de', 'fr']
        @site.config['default_lang'] = 'en'
        @site.prepare

        docs = [
          Jekyll::Document.new('about-en.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/about/'
          end,
          Jekyll::Document.new('about-es.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'es'
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/es/about/'
          end
        ]

        @site.assignPageLanguagePermalinks(docs[0], docs)

        expect(docs[0].data['missing_languages']).to contain_exactly('de', 'fr')
      end

      it 'sets missing_languages to [] when only one translation exists (single-source page)' do
        # Documents the comment's intent at site.rb:248–250: a single-source
        # page falls back identically everywhere, so nothing is "missing".
        @site.config['languages'] = ['en', 'es', 'de']
        @site.config['default_lang'] = 'en'
        @site.prepare

        docs = [
          Jekyll::Document.new('about-en.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/about/'
          end
        ]

        @site.assignPageLanguagePermalinks(docs[0], docs)

        expect(docs[0].data['permalink_lang']).to eq({ 'en' => '/about/' })
        expect(docs[0].data['available_languages']).to eq(['en'])
        expect(docs[0].data['missing_languages']).to eq([])
      end

      it 'unconditionally overwrites a frontmatter-set permalink_lang' do
        # Codifies the behavior change at site.rb:245 so removing/restoring
        # the unconditional overwrite is a deliberate decision next time.
        @site.config['languages'] = ['en', 'es']
        @site.config['default_lang'] = 'en'
        @site.prepare

        docs = [
          Jekyll::Document.new('about-en.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/about/'
            doc.data['permalink_lang'] = { 'en' => '/from-frontmatter/' }
          end,
          Jekyll::Document.new('about-es.md', site: @site, collection: @collection).tap do |doc|
            doc.data['lang'] = 'es'
            doc.data['page_id'] = 'about'
            doc.data['permalink'] = '/es/about/'
          end
        ]

        @site.assignPageLanguagePermalinks(docs[0], docs)

        expect(docs[0].data['permalink_lang']['en']).to eq('/about/')
        expect(docs[0].data['permalink_lang']).not_to have_value('/from-frontmatter/')
      end

      it 'assigns empty values when doc has no page_id and no usable permalink' do
        # Covers the "always runs" path introduced by removing the
        # `if !pageId.nil? && !pageId.empty?` outer guard.
        # Uses TestPage with empty url so normalized_permalink_for_doc returns
        # nil (Jekyll::Document would auto-generate a url and self-match).
        @site.config['languages'] = ['en', 'es']
        @site.config['default_lang'] = 'en'
        @site.prepare

        page = TestPage.new({ 'lang' => 'en' }, '', 'orphan.md')

        @site.assignPageLanguagePermalinks(page, [page])

        expect(page.data['permalink_lang']).to eq({})
        expect(page.data['available_languages']).to eq([])
        expect(page.data['missing_languages']).to eq([])
      end
    end

    describe 'i18n_headers Liquid tag — permalink-only path' do
      it 'matches translations by normalized permalink when page_id is absent' do
        # End-to-end coverage of Liquid → site.find_translations via the
        # permalink-only fallback. Uses lang-prefixed permalinks specifically
        # — this case would have failed under the prior raw-vs-normalized
        # comparison in build_lang_to_permalink.
        @site.config['baseurl'] = ''
        @site.config['url'] = 'https://test.github.io'
        @site.config['languages'] = ['en', 'es', 'de']
        @site.config['default_lang'] = 'en'
        @site.prepare

        collection = Jekyll::Collection.new(@site, 'test')
        docs = [
          Jekyll::Document.new('about-en.md', site: @site, collection: collection).tap do |doc|
            doc.data['lang'] = 'en'
            doc.data['permalink'] = '/about/'
          end,
          Jekyll::Document.new('about-es.md', site: @site, collection: collection).tap do |doc|
            doc.data['lang'] = 'es'
            doc.data['permalink'] = '/es/about/'
          end,
          Jekyll::Document.new('about-de.md', site: @site, collection: collection).tap do |doc|
            doc.data['lang'] = 'de'
            doc.data['permalink'] = '/de/about/'
          end
        ]
        @site.collections['test'] = collection
        collection.docs.concat(docs)

        page = docs[0].data.merge('permalink' => docs[0].data['permalink'])
        context = Liquid::Context.new({}, {}, { site: @site, page: page })
        output = Liquid::Template.parse('{% i18n_headers %}').render(context)

        expect(output).to include('hreflang="en"')
        expect(output).to include('hreflang="es"')
        expect(output).to include('hreflang="de"')
        expect(output).to include('href="https://test.github.io/es/about/"')
        expect(output).to include('href="https://test.github.io/de/about/"')
      end
    end
  end
end
