# frozen_string_literal: true

RSpec.describe SemverDialects::BaseVersion do # rubocop:todo Metrics/BlockLength
  let(:version) { described_class.new(tokens, addition:) }
  let(:tokens) { %w[1 2 3] }
  let(:addition) { described_class.new(addition_tokens) }
  let(:addition_tokens) { %w[alpha 1] }

  describe '#to_s' do
    subject do
      version.to_s
    end

    context 'with tokens' do
      let(:tokens) { %w[1 2 3] }

      context 'with an addition' do
        let(:addition_tokens) { %w[alpha 1] }

        it { is_expected.to eq '1.2.3-alpha.1' }
      end

      context 'with no addition' do
        let(:addition) { nil }

        it { is_expected.to eq '1.2.3' }
      end
    end

    context 'with no tokens' do
      let(:tokens) { [] }

      context 'with an addition' do
        let(:addition_tokens) { %w[alpha 2] }

        it { is_expected.to eq '-alpha.2' }
      end

      context 'with no addition' do
        let(:addition) { nil }

        it { is_expected.to eq '' }
      end
    end
  end

  describe '#is_zero?' do
    using RSpec::Parameterized::TableSyntax

    # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
    where(:tokens, :addition_tokens, :result) do
      [0, 0, 1] | nil | false
      [0, 0, 0] | nil | true
      [0, 0, 0] | [0, 0, 1] | false
      [0, 0, 0] | [0, 0, 0] | true
    end
    # rubocop:enable Lint/BinaryOperatorWithIdenticalOperands

    with_them do
      subject { version.is_zero? }

      let(:version) { described_class.new(tokens, addition:) }

      let(:addition) do
        return nil if addition_tokens.nil?

        described_class.new(addition_tokens)
      end

      it { is_expected.to eq(result) }
    end
  end

  describe '<=>' do
    subject { version.<=>(other) }

    let(:tokens) { [4, 5, 6] }

    let(:other) { described_class.new(other_tokens, addition: other_addition) }
    let(:other_tokens) { [4, 5, 6] }
    let(:other_addition) { described_class.new(other_addition_tokens) }
    let(:other_addition_tokens) { [4, 5, 6] }

    context 'when self has greater tokens' do
      let(:tokens) { [4, 5, 7] }
      let(:other_tokens) { [4, 5, 6] }

      it { is_expected.to eq 1 }
    end

    context 'when other has greater tokens' do
      let(:tokens) { [4, 5, 6] }
      let(:other_tokens) { [4, 5, 7] }

      it { is_expected.to eq(-1) }
    end

    context 'when versions have same tokens' do
      let(:other_tokens) { tokens }

      context 'when versions have no addition' do
        let(:addition) { nil }
        let(:other_addition) { nil }

        it { is_expected.to eq 0 }
      end

      context 'when versions have same addition' do
        let(:addition) { 'a' }
        let(:other_addition) { addition }

        it { is_expected.to eq 0 }
      end

      context 'when self has a greater addition' do
        let(:addition) { 'b' }
        let(:other_addition) { 'a' }

        it { is_expected.to eq 1 }
      end

      context 'when other has a greater addition' do
        let(:addition) { 'a' }
        let(:other_addition) { 'b' }

        it { is_expected.to eq(-1) }
      end

      context 'when only self has an addition' do
        let(:other_addition) { nil }
        let(:addition_tokens) { [] }

        context 'when the addition is positive' do
          let(:addition_tokens) { [0, 0, 1] }

          it { is_expected.to eq 1 }
        end

        context 'when the addition is neutral' do
          let(:addition_tokens) { [0, 0, 0] }

          it { is_expected.to eq 0 }
        end

        context 'when the addition is negative' do
          let(:addition_tokens) { [0, 0, -1] }

          it { is_expected.to eq(-1) }
        end
      end

      context 'when only other has an addition' do
        let(:addition) { nil }
        let(:other_addition_tokens) { [] }

        context 'when the addition is positive' do
          let(:other_addition_tokens) { [0, 0, 1] }

          it { is_expected.to eq(-1) }
        end

        context 'when the addition is neutral' do
          let(:other_addition_tokens) { [0, 0, 0] }

          it { is_expected.to eq 0 }
        end

        context 'when the addition is negative' do
          let(:other_addition_tokens) { [0, 0, -1] }

          it { is_expected.to eq 1 }
        end
      end
    end

    context 'when versions starts with same tokens' do
      let(:addition) { nil }
      let(:other_addition) { nil }

      context 'when other has extra zero tokens' do
        let(:other_tokens) { tokens + [0, 0, 0] }

        it { is_expected.to eq 0 }
      end

      context 'when other has extra non-zero tokens' do
        let(:other_tokens) { tokens + [0, 0, 1] }

        it { is_expected.to eq(-1) }
      end

      context 'when self has extra zero tokens' do
        let(:tokens) { other_tokens + [0, 0, 0] }

        it { is_expected.to eq 0 }
      end

      context 'when self has extra non-zero tokens' do
        let(:tokens) { other_tokens + [0, 0, 1] }

        it { is_expected.to eq 1 }
      end
    end
  end
end
