# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Style::Copyright, :config do
  let(:cop_config) { { 'Notice' => 'Copyright (\(c\) )?2015 Acme Inc' } }

  it 'does not register an offense when the notice is present' do
    expect_no_offenses(<<~RUBY)
      # Copyright 2015 Acme Inc.
      # test2
      names = Array.new
      names << 'James'
    RUBY
  end

  it 'does not register an offense when the notice is not the first comment' do
    expect_no_offenses(<<~RUBY)
      # test2
      # Copyright 2015 Acme Inc.
      names = Array.new
      names << 'James'
    RUBY
  end

  it 'does not register an offense when the notice is in a block comment' do
    expect_no_offenses(<<~RUBY)
      =begin
      blah, blah, blah
      Copyright 2015 Acme Inc.
      =end
      names = Array.new
      names << 'James'
    RUBY
  end

  context 'when multiline copyright notice' do
    let(:cop_config) do
      {
        'Notice' => <<~'COPYRIGHT'
          Copyright (\(c\) )?2015 Acme Inc.

          License details\.\.\.
        COPYRIGHT
      }
    end

    it 'does not register an offense when the multiline copyright notice is present' do
      cop_config['AutocorrectNotice'] = <<~COPYRIGHT
        # Copyright (c) 2015 Acme Inc.
        #
        # License details...
      COPYRIGHT

      expect_no_offenses(<<~RUBY)
        # Copyright 2015 Acme Inc.
        #
        # License details...
        class Foo
        end
      RUBY
    end

    it 'registers an offense when the multiline copyright notice is missing' do
      cop_config['AutocorrectNotice'] = <<~COPYRIGHT
        # Copyright (c) 2015 Acme Inc.
        #
        # License details...
      COPYRIGHT

      expect_offense(<<~RUBY)
        # Comment
        ^ Include a copyright notice matching [...]
        class Foo
        end
      RUBY

      expect_correction(<<~RUBY)
        # Copyright (c) 2015 Acme Inc.
        #
        # License details...

        # Comment
        class Foo
        end
      RUBY
    end
  end

  context 'when the copyright notice is missing' do
    let(:source) { <<~RUBY }
      # test
      ^ Include a copyright notice matching [...]
      # test2
      names = Array.new
      names << 'James'
    RUBY

    it 'adds an offense' do
      cop_config['AutocorrectNotice'] = '# Copyright (c) 2015 Acme Inc.'

      expect_offense(source)

      expect_correction(<<~RUBY)
        # Copyright (c) 2015 Acme Inc.
        # test
        # test2
        names = Array.new
        names << 'James'
      RUBY
    end

    it 'fails to autocorrect when the AutocorrectNotice does not match the Notice pattern' do
      cop_config['AutocorrectNotice'] = '# Copyleft (c) 2015 Acme Inc.'
      expect { expect_offense(source) }.to raise_error(RuboCop::Warning, %r{Style/Copyright:})
    end

    it 'fails to autocorrect if no AutocorrectNotice is given' do
      cop_config['AutocorrectNotice'] = nil
      expect { expect_offense(source) }.to raise_error(RuboCop::Warning, %r{Style/Copyright:})
    end
  end

  context 'when the copyright notice is missing and no `AutocorrectNotice` is configured' do
    include_context 'mock console output'

    before { cop_config['AutocorrectNotice'] = nil }

    # Investigate through a team without `raise_error` so that a raised `RuboCop::Warning`
    # is reported to stderr the way the runner does it, instead of being re-raised by
    # the default spec harness.
    def investigate_source(autocorrect:)
      cop.instance_variable_get(:@options)[:autocorrect] = autocorrect
      processed_source = parse_source("names = []\n")
      RuboCop::Cop::Team.new([cop], configuration).investigate(processed_source)
    end

    it 'warns on stderr when autocorrection is requested' do
      investigate_source(autocorrect: true)

      expect($stderr.string).to include(described_class::AUTOCORRECT_EMPTY_WARNING)
    end

    it 'registers an offense without warning on stderr during inspection' do
      report = investigate_source(autocorrect: false)

      expect(report.offenses.size).to eq(1)
      expect($stderr.string).to be_empty
    end
  end

  context 'when the copyright notice comes after any code' do
    it 'adds an offense' do
      cop_config['AutocorrectNotice'] = '# Copyright (c) 2015 Acme Inc.'

      expect_offense(<<~RUBY)
        # test2
        ^ Include a copyright notice matching [...]
        names = Array.new
        # Copyright (c) 2015 Acme Inc.
        names << 'James'
      RUBY

      expect_correction(<<~RUBY)
        # Copyright (c) 2015 Acme Inc.
        # test2
        names = Array.new
        # Copyright (c) 2015 Acme Inc.
        names << 'James'
      RUBY
    end
  end

  context 'when the source code file is empty' do
    it 'adds an offense' do
      cop_config['AutocorrectNotice'] = '# Copyright (c) 2015 Acme Inc.'

      expect_offense(<<~RUBY)
        ^{} Include a copyright notice matching [...]
      RUBY

      expect_no_corrections
    end
  end

  context 'when the copyright notice is missing and the source code file starts with a shebang' do
    it 'adds an offense' do
      cop_config['AutocorrectNotice'] = '# Copyright (c) 2015 Acme Inc.'

      expect_offense(<<~RUBY)
        #!/usr/bin/env ruby
        ^ Include a copyright notice matching [...]
        names = Array.new
        names << 'James'
      RUBY

      expect_correction(<<~RUBY)
        #!/usr/bin/env ruby
        # Copyright (c) 2015 Acme Inc.
        names = Array.new
        names << 'James'
      RUBY
    end
  end

  context 'when the copyright notice is missing and ' \
          'the source code file starts with an encoding comment' do
    it 'adds an offense' do
      cop_config['AutocorrectNotice'] = '# Copyright (c) 2015 Acme Inc.'

      expect_offense(<<~RUBY)
        # encoding: utf-8
        ^ Include a copyright notice matching [...]
        names = Array.new
        names << 'James'
      RUBY

      expect_correction(<<~RUBY)
        # encoding: utf-8
        # Copyright (c) 2015 Acme Inc.
        names = Array.new
        names << 'James'
      RUBY
    end
  end

  context 'when `AutocorrectNotice` does not start with a `#`' do
    let(:cop_config) do
      {
        'Notice' => '^Copyright (\(c\) )?2[0-9]{3} .+',
        'AutocorrectNotice' => 'Copyright (c) 2026 My Name'
      }
    end

    it 'inserts the notice as a comment line' do
      expect_offense(<<~RUBY)
        puts 'Hello world'
        ^ Include a copyright notice matching [...]
      RUBY

      expect_correction(<<~RUBY)
        # Copyright (c) 2026 My Name
        puts 'Hello world'
      RUBY
    end
  end

  context 'when the `Notice` pattern starts with `^#`' do
    let(:cop_config) do
      {
        'Notice' => '^# Copyright (\(c\) )?2[0-9]{3} .+',
        'AutocorrectNotice' => '# Copyright (c) 2026 My Name'
      }
    end

    it 'does not register an offense when the notice is present' do
      expect_no_offenses(<<~RUBY)
        # Copyright (c) 2026 My Name
        puts 'Hello world'
      RUBY
    end

    it 'autocorrects with a single `#` prefix' do
      expect_offense(<<~RUBY)
        puts 'Hello world'
        ^ Include a copyright notice matching [...]
      RUBY

      expect_correction(<<~RUBY)
        # Copyright (c) 2026 My Name
        puts 'Hello world'
      RUBY
    end
  end

  context 'when the `Notice` pattern starts with `\A#`' do
    let(:cop_config) do
      {
        'Notice' => '\A# Copyright (\(c\) )?2[0-9]{3} .+',
        'AutocorrectNotice' => '# Copyright (c) 2026 My Name'
      }
    end

    it 'does not register an offense when the notice is present' do
      expect_no_offenses(<<~RUBY)
        # Copyright (c) 2026 My Name
        puts 'Hello world'
      RUBY
    end

    it 'autocorrects with a single `#` prefix' do
      expect_offense(<<~RUBY)
        puts 'Hello world'
        ^ Include a copyright notice matching [...]
      RUBY

      expect_correction(<<~RUBY)
        # Copyright (c) 2026 My Name
        puts 'Hello world'
      RUBY
    end
  end

  context 'when the `Notice` pattern uses `\s+` after `#`' do
    let(:cop_config) do
      {
        'Notice' => '^#\s+Copyright (\(c\) )?2[0-9]{3} .+',
        'AutocorrectNotice' => '# Copyright (c) 2026 My Name'
      }
    end

    it 'does not register an offense when the notice is present' do
      expect_no_offenses(<<~RUBY)
        # Copyright (c) 2026 My Name
        puts 'Hello world'
      RUBY
    end

    it 'autocorrects with a single `#` prefix' do
      expect_offense(<<~RUBY)
        puts 'Hello world'
        ^ Include a copyright notice matching [...]
      RUBY

      expect_correction(<<~RUBY)
        # Copyright (c) 2026 My Name
        puts 'Hello world'
      RUBY
    end
  end

  context 'when the `Notice` pattern has multiple literal spaces after `#`' do
    let(:cop_config) do
      {
        'Notice' => '^#  Copyright (\(c\) )?2[0-9]{3} .+',
        'AutocorrectNotice' => '#  Copyright (c) 2026 My Name'
      }
    end

    it 'autocorrects preserving the configured spacing' do
      expect_offense(<<~RUBY)
        puts 'Hello world'
        ^ Include a copyright notice matching [...]
      RUBY

      expect_correction(<<~RUBY)
        #  Copyright (c) 2026 My Name
        puts 'Hello world'
      RUBY
    end
  end

  context 'when `Notice` starts with `^#` and AutocorrectNotice has no `#`' do
    let(:cop_config) do
      {
        'Notice' => '^# Copyright (\(c\) )?2[0-9]{3} .+',
        'AutocorrectNotice' => 'Copyright (c) 2026 My Name'
      }
    end

    it 'autocorrects to a single `#`-prefixed comment' do
      expect_offense(<<~RUBY)
        puts 'Hello world'
        ^ Include a copyright notice matching [...]
      RUBY

      expect_correction(<<~RUBY)
        # Copyright (c) 2026 My Name
        puts 'Hello world'
      RUBY
    end
  end

  context 'when `AutocorrectNotice` spans multiple lines without `#` prefixes' do
    let(:cop_config) do
      {
        'Notice' => <<~'COPYRIGHT',
          Copyright (\(c\) )?2026 Acme Inc.

          License details\.\.\.
        COPYRIGHT
        'AutocorrectNotice' => <<~COPYRIGHT
          Copyright (c) 2026 Acme Inc.

          License details...
        COPYRIGHT
      }
    end

    it 'prefixes each line with `# ` and emits blank lines as `#`' do
      expect_offense(<<~RUBY)
        class Foo
        ^ Include a copyright notice matching [...]
        end
      RUBY

      expect_correction(<<~RUBY)
        # Copyright (c) 2026 Acme Inc.
        #
        # License details...

        class Foo
        end
      RUBY
    end
  end

  context 'when the copyright notice is missing and ' \
          'the source code file starts with shebang and ' \
          'an encoding comment' do
    it 'adds an offense' do
      cop_config['AutocorrectNotice'] = '# Copyright (c) 2015 Acme Inc.'

      expect_offense(<<~RUBY)
        #!/usr/bin/env ruby
        ^ Include a copyright notice matching [...]
        # encoding: utf-8
        names = Array.new
        names << 'James'
      RUBY

      expect_correction(<<~RUBY)
        #!/usr/bin/env ruby
        # encoding: utf-8
        # Copyright (c) 2015 Acme Inc.
        names = Array.new
        names << 'James'
      RUBY
    end
  end
end
