# frozen_string_literal: true

RSpec.describe TTY::Prompt, "confirmation" do
  subject(:prompt) { TTY::Prompt::Test.new }

  context "#yes?" do
    it "agrees with question" do
      prompt.input << "yes"
      prompt.input.rewind
      expect(prompt.yes?("Are you a human?")).to eq(true)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(Y/n)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(Y/n)\e[0m y",
        "\e[2K\e[1GAre you a human? \e[90m(Y/n)\e[0m ye",
        "\e[2K\e[1GAre you a human? \e[90m(Y/n)\e[0m yes",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mYes\e[0m\n"
      ].join)
    end

    it "disagrees with question" do
      prompt.input << "no"
      prompt.input.rewind
      expect(prompt.yes?("Are you a human?")).to eq(false)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(Y/n)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(Y/n)\e[0m n",
        "\e[2K\e[1GAre you a human? \e[90m(Y/n)\e[0m no",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mno\e[0m\n"
      ].join)
    end

    it "warns about invalid entry when using defaults" do
      prompt.input << "test"
      prompt.input.rewind
      prompt.yes?("Are you a human?")
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(Y/n)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(Y/n)\e[0m t",
        "\e[2K\e[1GAre you a human? \e[90m(Y/n)\e[0m te",
        "\e[2K\e[1GAre you a human? \e[90m(Y/n)\e[0m tes",
        "\e[2K\e[1GAre you a human? \e[90m(Y/n)\e[0m test",
        "\e[31m>>\e[0m Invalid input.\e[1A",
        "\e[2K\e[1GAre you a human? \e[90m(Y/n)\e[0m ",
        "\e[2K\e[1G\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mYes\e[0m\n"
      ].join)
    end

    it "assumes default true" do
      prompt.input << "\r"
      prompt.input.rewind
      expect(prompt.yes?("Are you a human?")).to eq(true)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(Y/n)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(Y/n)\e[0m \n",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mYes\e[0m\n"
      ].join)
    end

    it "changes default" do
      prompt.input << "\n"
      prompt.input.rewind
      expect(prompt.yes?("Are you a human?", default: false)).to eq(false)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(y/N)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(y/N)\e[0m \n",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mNo\e[0m\n"
      ].join)
    end

    it "infers default value from a word" do
      prompt.input << "\n"
      prompt.input.rewind
      expect(prompt.yes?("Are you a human?", default: "no")).to eq(false)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(y/N)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(y/N)\e[0m \n",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mNo\e[0m\n"
      ].join)
    end

    it "fails to infer default value from a word" do
      prompt.input << "\n"
      prompt.input.rewind
      expect {
        prompt.yes?("Are you a human?", default: "unknown")
      }.to raise_error(TTY::Prompt::InvalidArgument,
                       "default needs to be `true` or `false`")
    end

    it "defaults suffix and converter" do
      prompt.input << "Nope\n"
      prompt.input.rewind
      result = prompt.yes?("Are you a human?") do |q|
        q.positive "Yup"
        q.negative "nope"
      end
      expect(result).to eq(false)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(Yup/nope)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(Yup/nope)\e[0m N",
        "\e[2K\e[1GAre you a human? \e[90m(Yup/nope)\e[0m No",
        "\e[2K\e[1GAre you a human? \e[90m(Yup/nope)\e[0m Nop",
        "\e[2K\e[1GAre you a human? \e[90m(Yup/nope)\e[0m Nope",
        "\e[2K\e[1GAre you a human? \e[90m(Yup/nope)\e[0m Nope\n",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mnope\e[0m\n"
      ].join)
    end

    it "defaults positive and negative" do
      prompt.input << "Nope\n"
      prompt.input.rewind
      result = prompt.yes?("Are you a human?") do |q|
        q.suffix "Yup/nope"
      end
      expect(result).to eq(false)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(Yup/nope)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(Yup/nope)\e[0m N",
        "\e[2K\e[1GAre you a human? \e[90m(Yup/nope)\e[0m No",
        "\e[2K\e[1GAre you a human? \e[90m(Yup/nope)\e[0m Nop",
        "\e[2K\e[1GAre you a human? \e[90m(Yup/nope)\e[0m Nope",
        "\e[2K\e[1GAre you a human? \e[90m(Yup/nope)\e[0m Nope\n",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mnope\e[0m\n"
      ].join)
    end

    it "accepts regex conflicting characters as suffix" do
      prompt.input << "]\n"
      prompt.input.rewind
      result = prompt.yes?("Are you a human? [ as yes and ] as no") do |q|
        q.suffix "[/]"
      end
      expect(result).to eq(false)
      expect(prompt.output.string).to eq([
        "Are you a human? [ as yes and ] as no \e[90m([/])\e[0m ",
        "\e[2K\e[1GAre you a human? [ as yes and ] as no \e[90m([/])\e[0m ]",
        "\e[2K\e[1GAre you a human? [ as yes and ] as no \e[90m([/])\e[0m ]\n",
        "\e[1A\e[2K\e[1G",
        "Are you a human? [ as yes and ] as no \e[32m]\e[0m\n"
      ].join)
    end

    it "customizes question through options" do
      prompt.input << "\r"
      prompt.input.rewind
      result = prompt.yes?("Are you a human?", suffix: "Agree/Disagree",
                                               positive: "Agree",
                                               negative: "Disagree")
      expect(result).to eq(true)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(Agree/Disagree)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m \n",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mAgree\e[0m\n"
      ].join)
    end

    it "customizes question through DSL" do
      prompt.input << "disagree\r"
      prompt.input.rewind
      conversion = proc { |input| !input.match(/^agree$/i).nil? }
      result = prompt.yes?("Are you a human?") do |q|
                 q.suffix "Agree/Disagree"
                 q.positive "Agree"
                 q.negative "Disagree"
                 q.convert conversion
               end
      expect(result).to eq(false)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(Agree/Disagree)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m d",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m di",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m dis",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m disa",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m disag",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m disagr",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m disagre",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m disagree",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m disagree\n",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mDisagree\e[0m\n"
      ].join)
    end

    it "obeys quiet mode" do
      prompt.input << "\r"
      prompt.input.rewind
      expect(prompt.yes?("Are you a human?", quiet: true)).to eq(true)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(Y/n)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(Y/n)\e[0m \n",
        "\e[1A\e[2K\e[1G"
      ].join)
    end
  end

  context "#no?" do
    it "agrees with question" do
      prompt.input << "no"
      prompt.input.rewind
      expect(prompt.no?("Are you a human?")).to eq(true)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(y/N)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(y/N)\e[0m n",
        "\e[2K\e[1GAre you a human? \e[90m(y/N)\e[0m no",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mNo\e[0m\n"
      ].join)
    end

    it "disagrees with question" do
      prompt.input << "yes"
      prompt.input.rewind
      expect(prompt.no?("Are you a human?")).to eq(false)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(y/N)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(y/N)\e[0m y",
        "\e[2K\e[1GAre you a human? \e[90m(y/N)\e[0m ye",
        "\e[2K\e[1GAre you a human? \e[90m(y/N)\e[0m yes",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32myes\e[0m\n"
      ].join)
    end

    it "warns about invalid entry when using defaults" do
      prompt.input << "test"
      prompt.input.rewind
      prompt.no?("Are you a human?")
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(y/N)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(y/N)\e[0m t",
        "\e[2K\e[1GAre you a human? \e[90m(y/N)\e[0m te",
        "\e[2K\e[1GAre you a human? \e[90m(y/N)\e[0m tes",
        "\e[2K\e[1GAre you a human? \e[90m(y/N)\e[0m test",
        "\e[31m>>\e[0m Invalid input.\e[1A",
        "\e[2K\e[1GAre you a human? \e[90m(y/N)\e[0m ",
        "\e[2K\e[1G\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mNo\e[0m\n"
      ].join)
    end

    it "assumes default false" do
      prompt.input << "\r"
      prompt.input.rewind
      expect(prompt.no?("Are you a human?")).to eq(true)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(y/N)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(y/N)\e[0m \n",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mNo\e[0m\n"
      ].join)
    end

    it "changes default" do
      prompt.input << "\r"
      prompt.input.rewind
      expect(prompt.no?("Are you a human?", default: true)).to eq(false)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(Y/n)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(Y/n)\e[0m \n",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mYes\e[0m\n"
      ].join)
    end

    it "defaults suffix and converter" do
      prompt.input << "Yup\n"
      prompt.input.rewind
      result = prompt.no?("Are you a human?") do |q|
        q.positive "yup"
        q.negative "Nope"
      end
      expect(result).to eq(false)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(yup/Nope)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(yup/Nope)\e[0m Y",
        "\e[2K\e[1GAre you a human? \e[90m(yup/Nope)\e[0m Yu",
        "\e[2K\e[1GAre you a human? \e[90m(yup/Nope)\e[0m Yup",
        "\e[2K\e[1GAre you a human? \e[90m(yup/Nope)\e[0m Yup\n",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32myup\e[0m\n"
      ].join)
    end

    it "customizes question through DSL" do
      prompt.input << "agree\r"
      prompt.input.rewind
      conversion = proc { |input| !input.match(/^agree$/i).nil? }
      result = prompt.no?("Are you a human?") do |q|
                 q.suffix "Agree/Disagree"
                 q.positive "Agree"
                 q.negative "Disagree"
                 q.convert conversion
               end
      expect(result).to eq(false)
      expect(prompt.output.string).to eq([
        "Are you a human? \e[90m(Agree/Disagree)\e[0m ",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m a",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m ag",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m agr",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m agre",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m agree",
        "\e[2K\e[1GAre you a human? \e[90m(Agree/Disagree)\e[0m agree\n",
        "\e[1A\e[2K\e[1G",
        "Are you a human? \e[32mAgree\e[0m\n"
      ].join)
    end
  end
end
