var filter = require('../lib/index').filter;
var assert = require('../lib/index').assert;
var sort = require('../lib/index').sort;
var reduce = require('../lib/index').reduce;

var fs = require('fs');
var should = require('chai').should();

describe('lib', function () {
    var resource = {};
    beforeEach(function (done) {
        fs.readFile('./samples/3201.json', {encoding: 'utf8'}, function (err, data) {
            if (err) return done(err);

            resource = JSON.parse(data);
            done();
        });
    });

    describe('can determine patient consent to share', function () {
        var consentGivenCodes = [
            {
                system: 'READ2',
                code: '9A1..'
            }
        ];

        var consentWithheldCodes = [
            {
                system: 'READ2',
                code: '9AX..'
            }
        ];

        var patientEntryActive = {
            content: {
                resourceType: 'Patient',
                active: true
            }
        };

        var patientEntryInactive = {
            content: {
                resourceType: 'Patient',
                active: false
            }
        };

        var observationEntryConsentGiven2004 = {
            content: {
                resourceType: 'Observation',
                name: {
                    coding: [
                        {
                            system: 'READ2',
                            code: '9A1..',
                            display: 'Consent given'
                        }
                    ]
                },
                issued: '2004-06-19T00:00:00+00:00'
            }
        };

        var observationEntryConsentGiven2014 = {
            content: {
                resourceType: 'Observation',
                name: {
                    coding: [
                        {
                            system: 'READ2',
                            code: '9A1..',
                            display: 'Consent given'
                        }
                    ]
                },
                issued: '2014-06-19T00:00:00+00:00'
            }
        };

        var observationEntryConsentWithdrawn2010 = {
            content: {
                resourceType: 'Observation',
                name: {
                    coding: [
                        {
                            system: 'READ2',
                            code: '9AX..',
                            display: 'Consent withdrawn'
                        }
                    ]
                },
                issued: '2010-06-19T00:00:00+00:00'
            }
        };

        var consentFn = function (resource) {
            function isActivePatient() {
                var patient = resource.entry.filter(filter.some(assert.entry.isResourceType('Patient')))[0];
                return patient.content.active !== false;
            }

            function consentsToShareInformation() {
                var entry = resource.entry
                    .filter(filter.some([assert.entry.hasCode(consentGivenCodes), assert.entry.hasCode(consentWithheldCodes)]))
                    .sort(sort.date(sort.order.DESC));

                var result = true;
                var latestConsentObs = entry[0];
                if (latestConsentObs) {
                    result = consentGivenCodes.reduce(function (prev, item) {
                        return item.code === latestConsentObs.content.name.coding[0].code && item.system === latestConsentObs.content.name.coding[0].system;
                    }, result);
                }

                return result;
            }

            return isActivePatient() && consentsToShareInformation();
        };

        it('should be able to accept a patient who is not inactive', function () {
            var resource = {
                resourceType: 'Bundle',
                entry: [
                    patientEntryActive
                ]
            };

            var result = consentFn(resource);

            result.should.be.true;
        });

        it('should be able to reject a patient who is inactive', function () {
            var resource = {
                resourceType: 'Bundle',
                entry: [
                    patientEntryInactive
                ]
            };

            var result = consentFn(resource);

            result.should.be.false;
        });

        it('should be able to accept a patient with implied consent', function () {
            var resource = {
                resourceType: 'Bundle',
                entry: [
                    patientEntryActive
                ]
            };

            var result = consentFn(resource);

            result.should.be.true;
        });

        it('should be able to accept a patient with consent explicitly given', function () {
            var resource = {
                resourceType: 'Bundle',
                entry: [
                    patientEntryActive,
                    observationEntryConsentGiven2004
                ]
            };

            var result = consentFn(resource);

            result.should.be.true;
        });

        it('should be able to reject a patient with consent explicitly withdrawn', function () {
            var resource = {
                resourceType: 'Bundle',
                entry: [
                    patientEntryActive,
                    observationEntryConsentWithdrawn2010
                ]
            };

            var result = consentFn(resource);

            result.should.be.false;
        });

        it('should be able to reject a patient with consent explicitly given and subsequently withdrawn', function () {
            var resource = {
                resourceType: 'Bundle',
                entry: [
                    patientEntryActive,
                    observationEntryConsentGiven2004,
                    observationEntryConsentWithdrawn2010
                ]
            };

            var result = consentFn(resource);

            result.should.be.false;
        });

        it('should be able to accept a patient with consent withheld and subsequently explicitly given', function () {
            var resource = {
                resourceType: 'Bundle',
                entry: [
                    patientEntryActive,
                    observationEntryConsentGiven2014,
                    observationEntryConsentWithdrawn2010
                ]
            };

            var result = consentFn(resource);

            result.should.be.true;
        });
    });

    it('can filter for a code from a given system', function () {

        var coding = [
            {
                system: 'READ2',
                code: '9A1..',
                display: 'Consent given'
            },
            {
                system: 'UNITTEST',
                code: 'XYZ..',
                display: 'Consent given'
            }
        ];

        var assertion = assert.object.has({system: 'READ2'});
        var result = coding.filter(filter.all(assertion));

        should.exist(result);
        result.length.should.equal(1);
        result[0].system.should.equal('READ2');
    });
});

