'use strict';

var _ = require('lodash');
var request = require('supertest');
var should = require('should');
var language = require('../lib/language')();
var _moment = require('moment');

describe('Treatment API', function ( ) {
  this.timeout(10000);
  var self = this;

  var api_secret_hash = 'b723e97aa97846eb92d5264f084b2823f57c4aa1';

  var api = require('../lib/api/');
  
  // Use before() instead of beforeEach() for app setup - boots once for all tests
  before(function (done) {
    process.env.API_SECRET = 'this is my long pass phrase';
    self.env = require('../lib/server/env')();
    self.env.settings.authDefaultRoles = 'readable';
    self.env.settings.enable = ['careportal', 'api'];
    this.wares = require('../lib/middleware/')(self.env);
    self.app = require('express')();
    self.app.enable('api');
    require('../lib/server/bootevent')(self.env, language).boot(function booted(ctx) {
      self.ctx = ctx;
      self.ctx.ddata = require('../lib/data/ddata')();
      self.app.use('/api', api(self.env, ctx));
      done();
    });
  });

  after(function () {
    // delete process.env.API_SECRET;
  });

  it('post single treatments', function (done) {

    self.ctx.treatments.remove({ find: { created_at: { '$gte': '1999-01-01T00:00:00.000Z' } } }, function ( ) {
      var now = (new Date()).toISOString();
      request(self.app)
        .post('/api/treatments/')
        .set('api-secret', api_secret_hash || '')
        .send({eventType: 'Meal Bolus', created_at: now, carbs: '30', insulin: '2.00', preBolus: '15', glucose: 100, glucoseType: 'Finger', units: 'mg/dl', notes: '<IMG SRC="javascript:alert(\'XSS\');">'})
        .expect(200)
        .end(function (err) {
          if (err) {
            done(err);
          } else {
            self.ctx.treatments.list({}, function (err, list) {
              var sorted = _.sortBy(list, function (treatment) {
                return treatment.created_at;
              });
              sorted.length.should.equal(2);
              sorted[0].glucose.should.equal(100);
              sorted[0].notes.should.equal('<img>');
              should.not.exist(sorted[0].eventTime);
              sorted[0].insulin.should.equal(2);
              sorted[1].carbs.should.equal(30);
              done();
            });
          }
        });

    });
  });

  /*
  it('saving entry without created_at should fail', function (done) {

    self.ctx.treatments().remove({ }, function ( ) {
      request(self.app)
        .post('/api/treatments/')
        .set('api-secret', self.env.api_secret || '')
        .send({eventType: 'Meal Bolus', carbs: '30', insulin: '2.00', preBolus: '15', glucose: 100, glucoseType: 'Finger', units: 'mg/dl'})
        .expect(422)
        .end(function (err) {
          if (err) {
            done(err);
          } else {
              done();
          }
        });
    });
  });
*/

  it('post single treatments in zoned time format', function (done) {
   
    var current_time = Date.now();
    console.log('Testing date with local format: ', _moment(current_time).format("YYYY-MM-DDTHH:mm:ss.SSSZZ"));

    self.ctx.treatments.remove({ find: { created_at: { '$gte': '1999-01-01T00:00:00.000Z' } } }, function ( ) {
      request(self.app)
        .post('/api/treatments/')
        .set('api-secret', api_secret_hash || '')
        .send({eventType: 'Meal Bolus', created_at: _moment(current_time).format("YYYY-MM-DDTHH:mm:ss.SSSZZ"), carbs: '30', insulin: '2.00', glucose: 100, glucoseType: 'Finger', units: 'mg/dl'})
        .expect(200)
        .end(function (err) {
          if (err) {
            done(err);
          } else {
            self.ctx.treatments.list({}, function (err, list) {
              var sorted = _.sortBy(list, function (treatment) {
                return treatment.created_at;
              });
              console.log(sorted);
              sorted.length.should.equal(1);
              sorted[0].glucose.should.equal(100);
              should.not.exist(sorted[0].eventTime);
              sorted[0].insulin.should.equal(2);
              sorted[0].carbs.should.equal(30);
              var zonedTime = _moment(current_time).utc().format("YYYY-MM-DDTHH:mm:ss.SSS") + "Z";
              sorted[0].created_at.should.equal(zonedTime);
              sorted[0].utcOffset.should.equal(-1* new Date().getTimezoneOffset());
              done();
            });
          }
        });

    });
  });


  it('post a treatment array', function (done) {
    self.ctx.treatments.remove({ find: { created_at: { '$gte': '1999-01-01T00:00:00.000Z' } } }, function ( ) {
      var now = (new Date()).toISOString();
      request(self.app)
        .post('/api/treatments/')
        .set('api-secret', api_secret_hash || '')
        .send([
          {eventType: 'BG Check', created_at: now, glucose: 100, preBolus: '0', glucoseType: 'Finger', units: 'mg/dl', notes: ''}
          , {eventType: 'Meal Bolus', created_at: now, carbs: '30', insulin: '2.00', preBolus: '15', glucose: 100, glucoseType: 'Finger', units: 'mg/dl'}
         ])
        .expect(200)
        .end(function (err) {
          if (err) {
            done(err);
          } else {
            self.ctx.treatments.list({}, function (err, list) {
              list.length.should.equal(3);
              should.not.exist(list[0].eventTime);
              should.not.exist(list[1].eventTime);

              done();
            });
          }
        });
    });
  });

  it('post a treatment array and dedupe', function (done) {
    self.ctx.treatments.remove({ find: { created_at: { '$gte': '1999-01-01T00:00:00.000Z' } } }, function ( ) {
      var now = (new Date()).toISOString();
      request(self.app)
        .post('/api/treatments/')
        .set('api-secret', api_secret_hash || '')
        .send([
          {eventType: 'BG Check', glucose: 100, units: 'mg/dl', created_at: now}
          , {eventType: 'BG Check', glucose: 100, units: 'mg/dl', created_at: now}
          , {eventType: 'BG Check', glucose: 100, units: 'mg/dl', created_at: now}
          , {eventType: 'BG Check', glucose: 100, units: 'mg/dl', created_at: now}
          , {eventType: 'BG Check', glucose: 100, units: 'mg/dl', created_at: now}
          , {eventType: 'BG Check', glucose: 100, units: 'mg/dl', created_at: now}
          , {eventType: 'BG Check', glucose: 100, units: 'mg/dl', created_at: now}
          , {eventType: 'BG Check', glucose: 100, units: 'mg/dl', created_at: now}
          , {eventType: 'Meal Bolus', created_at: now, carbs: '30', insulin: '2.00', preBolus: '15', glucose: 100, glucoseType: 'Finger', units: 'mg/dl'}
        ])
        .expect(200)
        .end(function (err) {
          if (err) {
            done(err);
          } else {
            self.ctx.treatments.list({}, function (err, list) {
              var sorted = _.sortBy(list, function (treatment) {
                return treatment.created_at;
              });

              if (sorted.length !== 3) {
                console.info('unexpected result length, sorted treatments:', sorted);
              }
              sorted.length.should.equal(3);
              sorted[0].glucose.should.equal(100);

              done();
            });
          }
        });
    });
  });

  it('post a treatment, query, delete, verify gone', function (done) {
    // insert a treatment - needs to be unique from example data
    console.log('Inserting treatment entry');
    var now = (new Date()).toISOString();
    request(self.app)
      .post('/api/treatments/')
      .set('api-secret', api_secret_hash || '')
      .send({eventType: 'Meal Bolus', created_at: now, carbs: '99', insulin: '2.00', preBolus: '15', glucose: 100, glucoseType: 'Finger', units: 'mg/dl'})
      .expect(200)
      .end(function (err) {
        if (err) {
          done(err);
        } else {
          // make sure treatment was inserted successfully
          console.log('Ensuring treatment entry was inserted successfully');
          request(self.app)
            .get('/api/treatments/')
            .query('find[carbs]=99')
            .set('api-secret', api_secret_hash || '')
            .expect(200)
            .expect(function (response) {
              response.body[0].carbs.should.equal(99);
            })
            .end(function (err) {
              if (err) {
                done(err);
              } else {
                // delete the treatment
                console.log('Deleting test treatment entry');
                request(self.app)
                  .delete('/api/treatments/')
                  .query('find[carbs]=99')
                  .set('api-secret', api_secret_hash || '')
                  .expect(200)
                  .end(function (err) {
                    if (err) {
                      done(err);
                    } else {
                      // make sure it was deleted
                      console.log('Testing if entry was deleted');
                      request(self.app)
                        .get('/api/treatments/')
                        .query('find[carbs]=99')
                        .set('api-secret', api_secret_hash || '')
                        .expect(200)
                        .expect(function (response) {
                          response.body.length.should.equal(0);
                        })
                        .end(done);
                    }
                  });
              }
            });
        }
      });
  });

  it('supports UUID treatment ids for post, put, and delete', function (done) {
    var treatmentId = '69F15FD2-8075-4DEB-AEA3-4352F455840D';
    // Use recent dates to avoid default query time filter (4 days window)
    var now = new Date();
    var originalCreatedAt = new Date(now.getTime() - 3600000).toISOString();  // 1 hour ago
    var repostedCreatedAt = new Date(now.getTime() - 1800000).toISOString();  // 30 min ago
    var updatedCreatedAt = new Date(now.getTime() - 900000).toISOString();    // 15 min ago

    self.ctx.treatments.remove({ find: { created_at: { '$gte': '1999-01-01T00:00:00.000Z' } } }, function () {
      request(self.app)
        .post('/api/treatments/')
        .set('api-secret', api_secret_hash || '')
        .send({
          _id: treatmentId,
          eventType: 'Temporary Override',
          created_at: originalCreatedAt,
          durationType: 'indefinite',
          correctionRange: [90, 110],
          insulinNeedsScaleFactor: 1.2,
          reason: 'test override'
        })
        .expect(200)
        .end(function (err, res) {
          if (err) {
            return done(err);
          }

          // REQ-SYNC-072: UUID _id is moved to identifier, _id is server-generated ObjectId
          var createdTreatment = res.body[0];
          createdTreatment.identifier.should.equal(treatmentId);
          createdTreatment._id.should.match(/^[0-9a-f]{24}$/);  // ObjectId format
          var serverId = createdTreatment._id;

          request(self.app)
            .post('/api/treatments/')
            .set('api-secret', api_secret_hash || '')
            .send({
              _id: treatmentId,
              eventType: 'Temporary Override',
              created_at: repostedCreatedAt,
              duration: 60,
              correctionRange: [90, 110],
              insulinNeedsScaleFactor: 1.2,
              reason: 'reposted override'
            })
            .expect(200)
            .end(function (err) {
              if (err) {
                return done(err);
              }

              // REQ-SYNC-072: Lookup by identifier
              self.ctx.treatments.list({ find: { identifier: treatmentId } }, function (err, list) {
                if (err) {
                  return done(err);
                }

                list.length.should.equal(1);
                list[0].identifier.should.equal(treatmentId);
                list[0].created_at.should.equal(repostedCreatedAt);
                list[0].duration.should.equal(60);
                should.not.exist(list[0].durationType);

                request(self.app)
                  .put('/api/treatments/')
                  .set('api-secret', api_secret_hash || '')
                  .send({
                    _id: treatmentId,
                    eventType: 'Temporary Override',
                    created_at: updatedCreatedAt,
                    duration: 30,
                    correctionRange: [90, 110],
                    insulinNeedsScaleFactor: 1.2,
                    reason: 'updated override'
                  })
                  .expect(200)
                  .end(function (err) {
                    if (err) {
                      return done(err);
                    }

                    self.ctx.treatments.list({ find: { identifier: treatmentId } }, function (err, updatedList) {
                      if (err) {
                        return done(err);
                      }

                      updatedList.length.should.equal(1);
                      updatedList[0].identifier.should.equal(treatmentId);
                      updatedList[0].created_at.should.equal(updatedCreatedAt);
                      updatedList[0].duration.should.equal(30);
                      updatedList[0].reason.should.equal('updated override');

                      // Delete by server-assigned _id (or could use identifier)
                      request(self.app)
                        .delete('/api/treatments/' + encodeURIComponent(serverId))
                        .set('api-secret', api_secret_hash || '')
                        .expect(200)
                        .end(function (err) {
                          if (err) {
                            return done(err);
                          }

                          self.ctx.treatments.list({ find: { identifier: treatmentId } }, function (err, deletedList) {
                            if (err) {
                              return done(err);
                            }

                            deletedList.length.should.equal(0);
                            done();
                          });
                        });
                    });
                  });
              });
            });
        });
    });
  });

  // ============================================================
  // REQ-SYNC-072: identifier-based CRUD (AAPS pattern)
  // AAPS sends explicit `identifier` field, not UUID as `_id`
  // ============================================================

  it('supports identifier field for AAPS-style treatments', function (done) {
    var identifier = 'AAPS-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
    var now = new Date();
    var createdAt = new Date(now.getTime() - 3600000).toISOString();

    self.ctx.treatments.remove({ find: { created_at: { '$gte': '1999-01-01T00:00:00.000Z' } } }, function () {
      // POST with explicit identifier (AAPS pattern)
      request(self.app)
        .post('/api/treatments/')
        .set('api-secret', api_secret_hash || '')
        .send({
          identifier: identifier,
          eventType: 'Bolus',
          insulin: 2.5,
          created_at: createdAt
        })
        .expect(200)
        .end(function (err, res) {
          if (err) {
            return done(err);
          }

          var createdTreatment = res.body[0];
          createdTreatment.identifier.should.equal(identifier);
          createdTreatment._id.should.match(/^[0-9a-f]{24}$/);  // Server-assigned ObjectId
          createdTreatment.insulin.should.equal(2.5);

          // Query by identifier
          self.ctx.treatments.list({ find: { identifier: identifier } }, function (err, list) {
            if (err) {
              return done(err);
            }

            list.length.should.equal(1);
            list[0].identifier.should.equal(identifier);
            done();
          });
        });
    });
  });

  it('deduplicates by identifier on re-upload', function (done) {
    var identifier = 'DEDUP-' + Date.now();
    var now = new Date();
    var createdAt = new Date(now.getTime() - 3600000).toISOString();

    self.ctx.treatments.remove({ find: { created_at: { '$gte': '1999-01-01T00:00:00.000Z' } } }, function () {
      // First POST
      request(self.app)
        .post('/api/treatments/')
        .set('api-secret', api_secret_hash || '')
        .send({
          identifier: identifier,
          eventType: 'Carb Correction',
          carbs: 30,
          created_at: createdAt
        })
        .expect(200)
        .end(function (err, res) {
          if (err) {
            return done(err);
          }

          var firstId = res.body[0]._id;

          // Second POST with same identifier - should upsert
          request(self.app)
            .post('/api/treatments/')
            .set('api-secret', api_secret_hash || '')
            .send({
              identifier: identifier,
              eventType: 'Carb Correction',
              carbs: 45,  // Updated value
              created_at: createdAt
            })
            .expect(200)
            .end(function (err, res) {
              if (err) {
                return done(err);
              }

              var secondId = res.body[0]._id;

              // Should be same document (upserted)
              secondId.should.equal(firstId);
              res.body[0].carbs.should.equal(45);

              // Verify only one document exists
              self.ctx.treatments.list({ find: { identifier: identifier } }, function (err, list) {
                if (err) {
                  return done(err);
                }

                list.length.should.equal(1);
                done();
              });
            });
        });
    });
  });

  it('supports batch upload with identifiers', function (done) {
    var identifiers = [
      'BATCH-1-' + Date.now(),
      'BATCH-2-' + Date.now(),
      'BATCH-3-' + Date.now()
    ];
    var now = new Date();

    self.ctx.treatments.remove({ find: { created_at: { '$gte': '1999-01-01T00:00:00.000Z' } } }, function () {
      var treatments = identifiers.map(function (id, idx) {
        return {
          identifier: id,
          eventType: 'Bolus',
          insulin: 1.0 + idx * 0.5,
          created_at: new Date(now.getTime() - (3 - idx) * 3600000).toISOString()
        };
      });

      request(self.app)
        .post('/api/treatments/')
        .set('api-secret', api_secret_hash || '')
        .send(treatments)
        .expect(200)
        .end(function (err, res) {
          if (err) {
            return done(err);
          }

          res.body.length.should.equal(3);

          // Verify identifiers preserved in order
          res.body[0].identifier.should.equal(identifiers[0]);
          res.body[1].identifier.should.equal(identifiers[1]);
          res.body[2].identifier.should.equal(identifiers[2]);

          // All should have ObjectId _id
          res.body.forEach(function (t) {
            t._id.should.match(/^[0-9a-f]{24}$/);
          });

          done();
        });
    });
  });
});
