text: 'use strict';
  
  require('../../support/test-helper');
  
  var assert = require('../../support/assert');
  var TestClient = require('../../support/test-client');
  
  function makeMapconfig (sql, cartocss) {
      return {
          version: '1.4.0',
          layers: [
              {
                  type: 'mapnik',
                  options: {
                      cartocss_version: '2.3.0',
                      sql: sql,
                      cartocss: cartocss
                  }
              }
          ]
      };
  }
  
  describe('turbo-carto regressions', function () {
      afterEach(function (done) {
          if (this.testClient) {
              this.testClient.drain(done);
          } else {
              done();
          }
      });
  
      it('should accept // comments', function (done) {
          var cartocss = [
              '/** simple visualization */',
              '',
              'Map {',
              '  buffer-size: 256;',
              '}',
              '',
              '#county_points_with_population{',
              '  marker-fill-opacity: 0.1;',
              '  marker-line-color:#FFFFFF;//#CF1C90;',
              '  marker-line-width: 0;',
              '  marker-line-opacity: 0.3;',
              '  marker-placement: point;',
              '  marker-type: ellipse;',
              '  //marker-comp-op: overlay;',
              '  marker-width: [cartodb_id];',
              '  [zoom=5]{marker-width: [cartodb_id]*2;}',
              '  [zoom=6]{marker-width: [cartodb_id]*4;}',
              '  marker-fill: #000000;',
              '  marker-allow-overlap: true;',
              '  ',
              '',
              '}'
          ].join('\n');
  
          this.testClient = new TestClient(makeMapconfig('SELECT * FROM populated_places_simple_reduced', cartocss));
          this.testClient.getLayergroup(function (err, layergroup) {
              assert.ok(!err, err);
  
              assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid'));
              assert.ok(!Object.prototype.hasOwnProperty.call(layergroup, 'errors'));
  
              done();
          });
      });
  
      it('should fail for private tables', function (done) {
          var cartocss = [
              '#private_table {',
              '  marker-placement: point;',
              '  marker-allow-overlap: true;',
              '  marker-line-width: 0;',
              '  marker-fill-opacity: 1.0;',
              '  marker-width: ramp([cartodb_id], 10, 20);',
              '  marker-fill: red;',
              '}'
          ].join('\n');
  
          this.testClient = new TestClient(makeMapconfig('SELECT * FROM test_table_private_1', cartocss));
          this.testClient.getLayergroup({ response: TestClient.RESPONSE.ERROR }, function (err, layergroup) {
              assert.ok(!err, err);
  
              assert.ok(!Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid'));
              assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'errors'));
  
              var turboCartoError = layergroup.errors_with_context[0];
              assert.ok(turboCartoError);
              assert.strictEqual(turboCartoError.type, 'layer');
              assert.ok(turboCartoError.message.match(/permission\sdenied\sfor\s.+?test_table_private_1/));
  
              done();
          });
      });
  
      it('should work for private tables with api key', function (done) {
          var cartocss = [
              '#private_table {',
              '  marker-placement: point;',
              '  marker-allow-overlap: true;',
              '  marker-line-width: 0;',
              '  marker-fill-opacity: 1.0;',
              '  marker-width: ramp([cartodb_id], 10, 20);',
              '  marker-fill: red;',
              '}'
          ].join('\n');
  
          this.testClient = new TestClient(makeMapconfig('SELECT * FROM test_table_private_1', cartocss), 1234);
          this.testClient.getLayergroup(function (err, layergroup) {
              assert.ok(!err, err);
  
              assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid'));
              assert.ok(!Object.prototype.hasOwnProperty.call(layergroup, 'errors'));
  
              done();
          });
      });
  
      it('should work with mapnik substitution tokens', function (done) {
          var cartocss = [
              '#layer {',
              '  line-width: 2;',
              '  line-color: #3B3B58;',
              '  line-opacity: 1;',
              '  polygon-opacity: 0.7;',
              '  polygon-fill: ramp([points_count], (#E5F5F9,#99D8C9,#2CA25F))',
              '}'
          ].join('\n');
  
          var sql = [
              'WITH hgrid AS (',
              '  SELECT CDB_HexagonGrid(',
              '    ST_Expand(!bbox!, greatest(!pixel_width!,!pixel_height!) * 100),',
              '    greatest(!pixel_width!,!pixel_height!) * 100',
              '  ) as cell',
              ')',
              'SELECT',
              '  hgrid.cell as the_geom_webmercator,',
              '  count(1) as points_count,',
              '  count(1)/power(100 * CDB_XYZ_Resolution(CDB_ZoomFromScale(!scale_denominator!)), 2) as points_density,',
              '  1 as cartodb_id',
              'FROM hgrid, (SELECT * FROM populated_places_simple_reduced) i',
              'where ST_Intersects(i.the_geom_webmercator, hgrid.cell)',
              'GROUP BY hgrid.cell'
          ].join('\n');
  
          this.testClient = new TestClient(makeMapconfig(sql, cartocss));
          this.testClient.getLayergroup(function (err, layergroup) {
              assert.ok(!err, err);
  
              assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid'));
              assert.ok(!Object.prototype.hasOwnProperty.call(layergroup, 'errors'));
  
              done();
          });
      });
  
      it('should work with mapnik substitution tokens and analyses', function (done) {
          var cartocss = [
              '#layer {',
              '  line-width: 2;',
              '  line-color: #3B3B58;',
              '  line-opacity: 1;',
              '  polygon-opacity: 0.7;',
              '  polygon-fill: ramp([points_count], (#E5F5F9,#99D8C9,#2CA25F))',
              '}'
          ].join('\n');
  
          var sqlWrap = [
              'WITH hgrid AS (',
              '  SELECT CDB_HexagonGrid(',
              '    ST_Expand(!bbox!, greatest(!pixel_width!,!pixel_height!) * 100),',
              '    greatest(!pixel_width!,!pixel_height!) * 100',
              '  ) as cell',
              ')',
              'SELECT',
              '  hgrid.cell as the_geom_webmercator,',
              '  count(1) as points_count,',
              '  count(1)/power(100 * CDB_XYZ_Resolution(CDB_ZoomFromScale(!scale_denominator!)), 2) as points_density,',
              '  1 as cartodb_id',
              'FROM hgrid, (<%= sql %>) i',
              'where ST_Intersects(i.the_geom_webmercator, hgrid.cell)',
              'GROUP BY hgrid.cell'
          ].join('\n');
  
          var mapConfig = {
              version: '1.5.0',
              layers: [
                  {
                      type: 'mapnik',
                      options: {
                          cartocss_version: '2.3.0',
                          source: {
                              id: 'head'
                          },
                          sql_wrap: sqlWrap,
                          cartocss: cartocss
                      }
                  }
              ],
              analyses: [
                  {
                      id: 'head',
                      type: 'source',
                      params: {
                          query: 'SELECT * FROM populated_places_simple_reduced'
                      }
                  }
              ]
          };
  
          this.testClient = new TestClient(mapConfig, 1234);
          this.testClient.getLayergroup(function (err, layergroup) {
              assert.ok(!err, err);
  
              assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid'));
              assert.ok(!Object.prototype.hasOwnProperty.call(layergroup, 'errors'));
  
              done();
          });
      });
  
      describe('empty datasource results', function () {
          afterEach(function (done) {
              if (this.testClient) {
                  this.testClient.drain(done);
              } else {
                  done();
              }
          });
  
          function emptyResultMapConfig (markerFillRule) {
              var cartocss = [
                  '#county_points_with_population {',
                  '  marker-placement: point;',
                  '  marker-allow-overlap: true;',
                  '  marker-fill-opacity: 1.0;',
                  '  marker-fill: ' + markerFillRule + ';',
                  '  marker-line-width: 0;',
                  '}'
              ].join('\n');
  
              return {
                  version: '1.5.0',
                  layers: [
                      {
                          type: 'mapnik',
                          options: {
                              cartocss_version: '2.3.0',
                              source: {
                                  id: 'head'
                              },
                              cartocss: cartocss
                          }
                      }
                  ],
                  analyses: [
                      {
                          id: 'head',
                          type: 'source',
                          params: {
                              query: 'SELECT * FROM populated_places_simple_reduced limit 0'
                          }
                      }
                  ]
              };
          }
  
          var methods = ['quantiles', 'equal', 'jenks', 'headtails', 'category'];
  
          methods.forEach(function (method) {
              it('should work for "' + method + '" method', function (done) {
                  var makerFillRule = 'ramp([pop_max], (#E5F5F9,#99D8C9,#2CA25F), ' + method + ')';
  
                  this.testClient = new TestClient(emptyResultMapConfig(makerFillRule), 1234);
                  this.testClient.getLayergroup(function (err, layergroup) {
                      assert.ok(!err, err);
  
                      assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid'));
                      assert.ok(!Object.prototype.hasOwnProperty.call(layergroup, 'errors'));
  
                      done();
                  });
              });
          });
      });
  
      var scenarios = [
          {
              desc: 'numeric datasource',
              cartocss: [
                  '#points {',
                  '  marker-fill: ramp([scalerank], colorbrewer(Reds), category);',
                  '}'
              ].join('\n'),
              expected: [
                  '#points {',
                  '  marker-fill: #fee5d9;',
                  '  [ scalerank = 6 ] {',
                  '    marker-fill: #fcae91',
                  '  }',
                  '  [ scalerank = 8 ] {',
                  '    marker-fill: #fb6a4a',
                  '  }',
                  '  [ scalerank = 4 ] {',
                  '    marker-fill: #de2d26',
                  '  }',
                  '  [ scalerank = 10 ] {',
                  '    marker-fill: #a50f15',
                  '  }',
                  '}'
              ].join('\n')
          },
          {
              desc: 'string datasource',
              cartocss: [
                  '#points {',
                  '  marker-fill: ramp([adm0name], colorbrewer(Reds), category);',
                  '}'
              ].join('\n'),
              expected: [
                  '#points {',
                  '  marker-fill: #fee5d9;',
                  '  [ adm0name = "Russia" ] {',
                  '    marker-fill: #fcae91',
                  '  }',
                  '  [ adm0name = "China" ] {',
                  '    marker-fill: #fb6a4a',
                  '  }',
                  '  [ adm0name = "Brazil" ] {',
                  '    marker-fill: #de2d26',
                  '  }',
                  '  [ adm0name = "Canada" ] {',
                  '    marker-fill: #a50f15',
                  '  }',
                  '}'
              ].join('\n')
          },
          {
              desc: 'numeric manual',
              cartocss: [
                  '#points {',
                  '  marker-fill: ramp([scalerank], colorbrewer(Reds), (-1, 6, 8, 4, 10), category);',
                  '}'
              ].join('\n'),
              expected: [
                  '#points {',
                  '  marker-fill: #fee5d9;',
                  '  [ scalerank = 6 ] {',
                  '    marker-fill: #fcae91',
                  '  }',
                  '  [ scalerank = 8 ] {',
                  '    marker-fill: #fb6a4a',
                  '  }',
                  '  [ scalerank = 4 ] {',
                  '    marker-fill: #de2d26',
                  '  }',
                  '  [ scalerank = 10 ] {',
                  '    marker-fill: #a50f15',
                  '  }',
                  '}'
              ].join('\n')
          }
      ];
  
      scenarios.forEach(function (scenario) {
          it('category ramps should use original type: ' + scenario.desc, function (done) {
              var mapConfig = makeMapconfig('SELECT * FROM populated_places_simple_reduced', scenario.cartocss);
              this.testClient = new TestClient(mapConfig);
              this.testClient.getLayergroup(function (err, layergroup) {
                  assert.ok(!err, err);
  
                  assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid'));
                  assert.deepStrictEqual(layergroup.metadata.layers[0].meta.cartocss, scenario.expected);
  
                  done();
              });
          });
      });
  
      describe('Buckets calculation', function () {
          afterEach(function (done) {
              if (this.testClient) {
                  this.testClient.drain(done);
              } else {
                  done();
              }
          });
  
          const scenarios = [
              {
                  numBuckets: 1,
                  bucketResponse: [
                      {
                          filter: {
                              type: 'range',
                              start: 0,
                              end: 8
                          },
                          value: 1
                      }
                  ]
              },
              {
                  numBuckets: 2,
                  bucketResponse: [
                      {
                          filter: {
                              type: 'range',
                              start: 0,
                              end: 3
                          },
                          value: 1
                      },
                      {
                          filter: {
                              type: 'range',
                              start: 3,
                              end: 8
                          },
                          value: 20
                      }
                  ]
              },
              {
                  numBuckets: 3,
                  bucketResponse: [
                      {
                          filter: {
                              type: 'range',
                              start: 0,
                              end: 2
                          },
                          value: 1
                      },
                      {
                          filter: {
                              type: 'range',
                              start: 2,
                              end: 5
                          },
                          value: 10.5
                      },
                      {
                          filter: {
                              type: 'range',
                              start: 5,
                              end: 8
                          },
                          value: 20
                      }
                  ]
              }
          ];
  
          scenarios.forEach(function (scenario) {
              it('Buckets: ' + scenario.numBuckets, function (done) {
                  const bucketsMapConfig = makeMapconfig({ numQuantiles: scenario.numBuckets });
  
                  this.testClient = new TestClient(bucketsMapConfig);
                  this.testClient.getLayergroup({ response: OK_RESPONSE }, function (err, layergroup) {
                      const rule = layergroup.metadata.layers[0].meta.cartocss_meta.rules[0];
  
                      assert.ok(!err, err);
                      assert.strictEqual(rule.buckets.length, scenario.numBuckets);
                      assert.deepStrictEqual(rule.buckets, scenario.bucketResponse);
  
                      done();
                  });
              });
          });
  
          function makeMapconfig ({ numQuantiles = 1 }) {
              return {
                  version: '1.4.0',
                  layers: [
                      {
                          type: 'mapnik',
                          options: {
                              cartocss_version: '2.3.0',
                              sql: 'SELECT * FROM populated_places_simple_reduced',
                              cartocss: `#layer {\n
                                          marker-width: ramp([labelrank], range(1, 20), quantiles(${numQuantiles}));\n
                                          marker-fill: #EE4D5A;\n  marker-fill-opacity: 0.9;\n
                                          marker-allow-overlap: true;\n  marker-line-width: 1;\n
                                          marker-line-color: #FFFFFF;\n  marker-line-opacity: 1;\n}`
                          }
                      }
                  ]
              };
          }
  
          const OK_RESPONSE = {
              status: 200,
              headers: {
                  'Content-Type': 'application/json; charset=utf-8'
              }
          };
      });
  });
  