/*
 * Copyright (C) 2017 Centro de Computacao Cientifica e Software Livre
 * Departamento de Informatica - Universidade Federal do Parana
 *
 * This file is part of blendb.
 *
 * blendb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * blendb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with blendb.  If not, see <http://www.gnu.org/licenses/>.
 */

import * as request from "supertest";
import { expect } from "chai";
import * as server from "../../main";
import { Adapter } from "../../core/adapter";
import { ConfigParser } from "../../util/configParser";
import { Fixture as FixPostgres } from "../../../test/postgres/fixture";
import { Fixture as FixMonet } from "../../../test/monet/fixture";
import { MonetAdapter, MonetConfig } from "../../adapter/monet";
import { PostgresAdapter } from "../../adapter/postgres";

describe("API collect controller", () => {

    // Initializing
    let config: any;
    let adapter: Adapter;
    let fixture;
    before(function (done): void {
        // Arrow function not used to get acces to this and skip the test
        const configPath =  process.env.BLENDB_SCHEMA_FILE;
        config = ConfigParser.parse(configPath);
        if (config.adapter === "postgres") {
            fixture = new FixPostgres(config.connection);
            fixture.loadSource(config.sources, (err) => {
                if (err) {
                    throw err;
                }
                adapter = new PostgresAdapter(config.connection);
                done();
            });
        }
        else if (config.adapter === "monet") {
            fixture = new FixMonet(config.connection);
            fixture.loadSource(config.sources, (err) => {
                if (err) {
                    throw err;
                }
                let parsedConfig: MonetConfig = {
                    user: config.connection.user,
                    dbname: config.connection.database,
                    password: config.connection.password,
                    host: config.connection.host,
                    port: config.connection.port
                };
                adapter = new MonetAdapter(parsedConfig);
                done();
            });
        }
        else {
            this.skip();
        }
    });
    it("should respond 500 when req.params.class does not exist on Sources", (done) => {
        request(server)
            .post("/v1/collect/thisisjustatest")
            .send({"fields:1": 1, "fields:2": 2})
            .expect(500)
            .expect((res: any) => { 
                const message = "Query execution failed: " +
                "Could not construct query with the given parameters.";
                const error = "The source named 'thisisjustatest' was not found";
                expect(res.body).to.be.an("object");
                expect(res.body).to.have.property("message");
                expect(res.body.message).to.be.eql(message);
                expect(res.body.error).to.be.eql(error);
 
            })
            .end(done);
    });
    it("should respond 500 when name does not exist in Product from market", (done) => {
        request(server)
        .post("/v1/collect/Product")
        .send({
            "pricein": 17.51,
            "priceout": 30.55,
            "validity": "2018-05-16",
            "id": 5
        })
        .expect(500)
        .expect((res: any) => {
            const message = "Query execution failed: " +
            "Could not construct query with the given parameters.";
            const error = "The 'name' wasn't informed on json";
            expect(res.body).to.be.an("object");
            expect(res.body).to.have.property("message");
            expect(res.body.message).to.be.eql(message);
            expect(res.body.error).to.be.eql(error);
            })
            .end(done);
    });
    it("should respond 200 when data has been stored on Product", (done) => {
        request(server)
            .post("/v1/collect/Sell")
            .send({
                "Registered": false,
                "Product.id": 1,
                "Client.id": 1,
                "Seller.id": 3,
                "Quantity": 10,
                "Datein" : "2017-10-30"
             })
            .expect(200)
            .expect((res: any) => {
                const message = "Data has been successfully received and stored by the server";
                expect(res.body).to.be.an("object");
                expect(res.body).to.have.property("message");
                expect(res.body.message).to.be.eql(message);

            })
            .end(done);
    });
    it("should respond 500 when value isn't defined on enumtype ", (done) => {
        request(server)
            .post("/v1/collect/Seller")
            .send({
                "name": "radom",
                "age" : 25,
                "sex" : "thisisjustatest",
                "CPF" : "145.827.483-76",
                "id" : 4
            })
            .expect(500)
            .expect((res: any) => {
                const message = "Query execution failed: " +
                "Could not construct query with the given parameters.";
                const error = "The value 'thisisjustatest' from 'sex' isn't listed on enumsex";
                expect(res.body).to.be.an("object");
                expect(res.body).to.have.property("message");
                expect(res.body.message).to.be.eql(message);
                expect(res.body.error).to.be.eql(error);

            })
            .end(done);
    });
    it("should respond 500 when dataType from id isn't integer", (done) => {
        request(server)
            .post("/v1/collect/Product")
            .send({
                "name":"strategy",
                "pricein": 17.51,
                "priceout": 30.55,
                "validity": "1991-05-16",
                "id": "nope"
            })
            .expect(500)
            .expect((res: any) => {
                const message = "Query execution failed: " +
                "Could not construct query with the given parameters.";
                const error = "The value 'nope' from 'id' isn't a type integer";
                expect(res.body).to.be.an("object");
                expect(res.body).to.have.property("message");
                expect(res.body.message).to.be.eql(message);
                expect(res.body.error).to.be.eql(error);
            })
            .end(done);
    });
    it("should respond 500 when dataType from pricein isn't float", (done) => {
        request(server)
            .post("/v1/collect/Product")
            .send({
                "name": "strategy",
                "pricein": "notafloat",
                "priceout": 30.55,
                "validity": "1991-05-16",
                "id": 5
            })
            .expect(500)
            .expect((res: any) => {

                const message = "Query execution failed: " +
                "Could not construct query with the given parameters.";
                const error = "The value 'notafloat' from 'pricein' isn't a type float";
                expect(res.body).to.be.an("object");
                expect(res.body).to.have.property("message");
                expect(res.body.message).to.be.eql(message);
                expect(res.body.error).to.be.eql(error);

            })
            .end(done);
    });
    it("should respond 500 when dataType from name isn't string", (done) => {
        request(server)
            .post("/v1/collect/Client")
            .send({
                "name": 5,
                "CPF" : "500.345.583-65",
                "id" : 5
            })
            .expect(500)
            .expect((res: any) => {
                const message = "Query execution failed: " +
                "Could not construct query with the given parameters.";
                const error = "The value '5' from 'name' isn't a type string";
                expect(res.body).to.be.an("object");
                expect(res.body).to.have.property("message");
                expect(res.body.message).to.be.eql(message);
                expect(res.body.error).to.be.eql(error);
            })
            .end(done);
    });
    it("should respond 500 when dataType from fields:3 isn't boolean", (done) => {
        request(server)
            .post("/v1/collect/Sell")
            .send({
                "Registered": "notaboolean",
                "Product.id": 1,
                "Client.id": 9,
                "Seller.id": 12,
                "Quantity": 50,
                "Datein" : "1980-01-30"
             })
            .expect(500)
            .expect((res: any) => {

                const message = "Query execution failed: " +
                "Could not construct query with the given parameters.";
                const error = "The value 'notaboolean' from 'Registered' isn't a type boolean";
                expect(res.body).to.be.an("object");
                expect(res.body).to.have.property("message");
                expect(res.body.message).to.be.eql(message);
                expect(res.body.error).to.be.eql(error);

            })
            .end(done);
    });
    it("should respond 500 when the first dataType from Datein isn't a valid date", (done) => {
        request(server)
            .post("/v1/collect/Sell")
            .send({
                "Registered": "true",
                "Product.id": 9,
                "Client.id": 6,
                "Seller.id": 8,
                "Quantity": 23,
                "Datein" : "1999-25-25"
             })
            .expect(500)
            .expect((res: any) => {

                const message = "Query execution failed: " +
                "Could not construct query with the given parameters.";
                const error = "The value '1999-25-25' from 'Datein' isn't a type date";
                expect(res.body).to.be.an("object");
                expect(res.body).to.have.property("message");
                expect(res.body.message).to.be.eql(message);
                expect(res.body.error).to.be.eql(error);

            })
            .end(done);
    });
    it("should respond 500 when the first dataType from Datein isn't a valid format date", (done) => {
        request(server)
            .post("/v1/collect/Sell")
            .send({
                "Registered": "true",
                "Product.id": 5,
                "Client.id": 16,
                "Seller.id": 13,
                "Quantity": 7,
                "Datein" : "1999/12/12"
             })
            .expect(500)
            .expect((res: any) => {

                const message = "Query execution failed: " +
                "Could not construct query with the given parameters.";
                const error = "The value '1999/12/12' from 'Datein' isn't a type date";
                expect(res.body).to.be.an("object");
                expect(res.body).to.have.property("message");
                expect(res.body.message).to.be.eql(message);
                expect(res.body.error).to.be.eql(error);

            })
            .end(done);
    });
    it("should respond 200 when data has been stored on Seller", (done) => {
        request(server)
            .post("/v1/collect/Seller")
            .send({
                "name": "radom",
                "age" : 25,
                "sex" : "male",
                "CPF" : "145.827.483-76",
                "id" : 4
            })
            .expect(200)
            .expect((res: any) => {
                const message = "Data has been successfully received and stored by the server";
                expect(res.body).to.be.an("object");
                expect(res.body).to.have.property("message");
                expect(res.body.message).to.be.eql(message);

            })
            .end(done);
    });
});