use lib 'lib';
use lib 'specs/support';
use BDD::Behave;
use BloginTest;
use Blogin::Config;
use Blogin;
use Blogin::Log;

my $CONFIGURED = 'specs/fixtures/configured'.IO;


sub build-configured(IO::Path:D $target, *%options) {
  my $config = Blogin::Config.load($CONFIGURED.add('blogin.json'));

  build(
    src => $CONFIGURED.add('content'),
    config => $config,
    out => $target,
    log => Blogin::Log.new(:level('quiet')),
    |%options,
  );
}

describe 'reading blogin.json', {
  let(:config, { Blogin::Config.load($CONFIGURED.add('blogin.json')) });

  it 'reads the site title', {
    expect(config().title).to.eq('Configured Site');
  }

  it 'reads the page size', {
    expect(config().page-size).to.eq(2);
  }

  it 'reads the home section', {
    expect(config().home-section).to.eq('posts');
  }

  it 'reads the debug flag', {
    expect(config().debug).to.be-truthy;
  }

  it 'reads a per-section override', {
    expect(config().sections<essays><page-size>).to.eq(1);
  }
}

describe 'config defaults', {
  let(:config, { Blogin::Config.new });

  it 'defaults the output dir', {
    expect(config().output-dir).to.eq('public');
  }

  it 'defaults clean-urls to false so it works on any static host', {
    expect(config().clean-urls).to.be-falsy;
  }

  it 'defaults the css framework to none', {
    expect(config().css-framework).to.eq('none');
  }

  it 'defaults the summary length', {
    expect(config().summary-length).to.eq(200);
  }

  it 'defaults robots to true', {
    expect(config().robots).to.be-truthy;
  }

  it 'defaults the taxonomies to tags', {
    expect(config().taxonomies.join(',')).to.eq('tags');
  }

  it 'defaults the feed formats to atom', {
    expect(config().feed-formats.join(',')).to.eq('atom');
  }

  it 'defaults minify off', {
    expect(config().minify).to.be-falsy;
  }

  it 'defaults fingerprint off', {
    expect(config().fingerprint).to.be-falsy;
  }

  it 'defaults image widths to empty', {
    expect(config().image-widths.elems).to.eq(0);
  }

  it 'defaults reading words-per-minute', {
    expect(config().reading-wpm).to.eq(200);
  }

  it 'defaults the related count', {
    expect(config().related-count).to.eq(5);
  }
}

describe 'reading the metadata keys', {
  it 'reads a custom summary length', {
    expect(Blogin::Config.from-data(%( summary-length => 120 )).summary-length).to.eq(120);
  }

  it 'reads the robots toggle', {
    expect(Blogin::Config.from-data(%( robots => False )).robots).to.be-falsy;
  }

  it 'reads a custom taxonomy list', {
    my @taxonomies = Blogin::Config.from-data(%( taxonomies => ['tags', 'categories'] )).taxonomies;
    expect(@taxonomies.elems).to.eq(2);
  }

  it 'reads the second custom taxonomy name', {
    my @taxonomies = Blogin::Config.from-data(%( taxonomies => ['tags', 'categories'] )).taxonomies;
    expect(@taxonomies[1]).to.eq('categories');
  }

  it 'rejects a non-list taxonomies value', {
    try Blogin::Config.from-data(%( taxonomies => 'tags' ));
    expect($!.message.contains('taxonomies')).to.be-truthy;
  }

  it 'reads a custom feed-formats list', {
    my @formats = Blogin::Config.from-data(%( feed-formats => ['atom', 'json'] )).feed-formats;
    expect(@formats.join(',')).to.eq('atom,json');
  }

  it 'rejects an unknown feed format', {
    try Blogin::Config.from-data(%( feed-formats => ['atom', 'pdf'] ));
    expect($!.message.contains('feed-formats')).to.be-truthy;
  }

  it 'reads a custom image-widths list', {
    my @widths = Blogin::Config.from-data(%( image-widths => [320, 640] )).image-widths;
    expect(@widths.elems).to.eq(2);
  }

  it 'rejects a non-integer image width', {
    try Blogin::Config.from-data(%( image-widths => [320, 'big'] ));
    expect($!.message.contains('image-widths')).to.be-truthy;
  }

  it 'rejects a non-integer summary length', {
    try Blogin::Config.from-data(%( summary-length => 'lots' ));
    expect($!.message.contains('summary-length')).to.be-truthy;
  }
}

describe 'malformed config', {
  it 'reports the offending key on a bad type', {
    try Blogin::Config.from-data(%( page-size => 'ten' ));
    expect($!.message.contains('page-size')).to.be-truthy;
  }

  it 'reports the offending nested section key', {
    try Blogin::Config.from-data(%( sections => %( essays => %( order => 'high' ) ) ));
    expect($!.message.contains('sections.essays.order')).to.be-truthy;
  }

  it 'rejects a non-boolean date visibility flag', {
    try Blogin::Config.from-data(%( sections => %( essays => %( index-dates => 'nope' ) ) ));
    expect($!.message.contains('sections.essays.index-dates')).to.be-truthy;
  }
}

describe 'config driving the build', {
  let(:out, { temp-dir('config') });

  after-each { nuke(out()) }

  it 'passes the site title into the layouts', {
    build-configured(out());
    expect(out().add('index.html').slurp.contains('Configured Site')).to.be-truthy;
  }

  it 'renders the home section at the root', {
    build-configured(out());
    expect(out().add('index.html').e).to.be-truthy;
  }

  it 'paginates at the configured page size', {
    build-configured(out());
    expect(out().add('posts/page/2.html').e).to.be-truthy;
  }

  it 'applies a per-section page-size override', {
    build-configured(out());
    expect(out().add('essays/page/2.html').e).to.be-truthy;
  }

  it 'enables debug from config', {
    build-configured(out());
    expect(out().add('index.html').slurp.contains('<!--')).to.be-truthy;
  }

  it 'lets a flag override win over config debug', {
    build-configured(out(), debug => False);
    expect(out().add('index.html').slurp.contains('<!--')).to.be-falsy;
  }
}
