BEGIN;

    -- Load the TAP functions.
    CREATE EXTENSION pgtap;
    SET client_min_messages TO warning;

    -- Plan the tests.

    SELECT plan(64);

    -- Add data

    \i xt/data/42-pg/Base.sql
    \i xt/data/42-pg/Reconciliation.sql

    -- Validate required tables

    SELECT has_table('cr_report');
    SELECT has_table('cr_report_line');
    SELECT has_table('cr_coa_to_account');

    -- Validate required view

    SELECT has_view('recon_payee');

    -- Validate required triggers

    SELECT has_trigger('cr_report','block_change_when_approved');

    -- Validate required functions

    SELECT has_function('cr_report_block_changing_approved','{}'::text[]);
    SELECT has_function('reconciliation__account_list','{}'::text[]);
    SELECT has_function('reconciliation__add_entry',array['integer', 'text', 'text', 'timestamp without time zone', 'numeric']);
    SELECT has_function('reconciliation__check',array['date', 'integer']);
    SELECT has_function('reconciliation__delete_my_report',array['integer']);
    SELECT has_function('reconciliation__delete_unapproved',array['integer']);
    SELECT has_function('reconciliation__get_cleared_balance',array['integer', 'date', 'boolean']);
    SELECT has_function('reconciliation__get_current_balance',array['integer', 'date']);
    SELECT has_function('reconciliation__new_report',array['integer', 'numeric', 'date', 'boolean', 'bigint']);
    SELECT has_function('reconciliation__pending_transactions',array['integer', 'numeric']);
    SELECT has_function('reconciliation__previous_report_date',ARRAY['integer','date']);
    SELECT has_function('reconciliation__reject_set',array['integer']);
    SELECT has_function('reconciliation__report_approve',array['integer']);
    SELECT has_function('reconciliation__report_details',array['integer']);
    SELECT has_function('reconciliation__report_details_payee',array['integer']);
    SELECT has_function('reconciliation__report_details_payee_with_days',array['integer', 'date']);
    SELECT has_function('reconciliation__report_summary',array['integer']);
    SELECT has_function('reconciliation__save_set',array['integer', 'integer[]']);
    SELECT has_function('reconciliation__search',array['date', 'date', 'numeric', 'numeric', 'integer', 'boolean', 'boolean']);
    SELECT has_function('reconciliation__submit_set',array['integer']);

    -- Run tests

--    PREPARE test AS SELECT count(*)
--                      FROM defaults
--                      WHERE setting_key = 'check_prefix';
--    SELECT results_eq('test',ARRAY[1],'check_prefix set');

--    UPDATE defaults
--    SET value = 'Recon gl test '
--    WHERE setting_key = 'check_prefix';

    CREATE TEMPORARY TABLE test_parameters (id int);
    INSERT INTO test_parameters(id) VALUES(nextval('cr_report_id_seq'));

    PREPARE test AS SELECT reconciliation__previous_report_date(test_get_account_id('-11111'), now()::date);
    SELECT results_eq('test', ARRAY[]::cr_report[], 'No previous report');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__new_report(test_get_account_id('-11111'), 100, '1001-01-01', false,
        currval('workflow_seq'));
    SELECT results_eq('test', $$ SELECT id::bigint+1 FROM test_parameters $$, 'Create Recon Report');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__delete_my_report(currval('cr_report_id_seq')::int);
    SELECT results_eq('test',ARRAY[true],'Delete Recon Report');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__previous_report_date(test_get_account_id('-11111'), now()::date);
    SELECT results_eq('test', ARRAY[]::cr_report[], 'Deleted previous report doesn''t show up');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__new_report(test_get_account_id('-11111'), 100, '1001-01-01', false,
        currval('workflow_seq'));
    SELECT results_eq('test', $$ SELECT id::bigint+2 FROM test_parameters $$, 'Create Recon Report');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__pending_transactions(currval('cr_report_id_seq')::int, 110) > 0;
    SELECT results_eq('test',ARRAY[true],'Pending Transactions Ran');
    DEALLOCATE test;

    PREPARE test AS SELECT count(distinct ac.trans_id)::int
                      FROM acc_trans ac
                      JOIN cr_report_line_links rll on ac.entry_id = rll.entry_id
                      JOIN cr_report_line rl ON rll.report_line_id = rl.id
                      WHERE report_id = currval('cr_report_id_seq')::int;
    SELECT results_eq('test',Array[11],'Correct number of transactions 1');
    DEALLOCATE test;

    PREPARE test AS SELECT count(*)::int
                      FROM cr_report_line
                      WHERE scn LIKE '% gl %'
                      AND report_id = currval('cr_report_id_seq')::int;
    SELECT results_eq('test', ARRAY[2], 'Correct number of GL groups');
    DEALLOCATE test;

    PREPARE test AS SELECT count(*)::int
                      FROM cr_report_line
                      WHERE report_id = currval('cr_report_id_seq')::int;
    -- "3 sources (1,2,t gl 1) x 2 dates" == 6 transactions
    SELECT results_eq('test',ARRAY[6],'Correct number of report lines');
    DEALLOCATE test;

    select reconciliation__save_set(
           currval('cr_report_id_seq')::int,
           (select array_agg(id::int) from cr_report_line
             where report_id = currval('cr_report_id_seq')::int)
    );
    PREPARE test AS SELECT reconciliation__submit_set(currval('cr_report_id_seq')::int);
    SELECT results_eq('test',ARRAY[true],'Report Submitted');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__previous_report_date(test_get_account_id('-11111'), '1001-01-01');
    SELECT results_eq('test', ARRAY[]::cr_report[], 'No previous report before 1001-01-01');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__report_approve(currval('cr_report_id_seq')::int) > 0;
    SELECT results_eq('test',ARRAY[true],'1 Report Approved');
    DEALLOCATE test;

    PREPARE test AS SELECT end_date FROM reconciliation__previous_report_date(test_get_account_id('-11111'), '1001-01-02');
    SELECT results_eq('test', ARRAY['1001-01-01']::date[], 'One previous report at 1001-01-01');
    DEALLOCATE test;

    PREPARE test as SELECT count(*)::int
                      FROM acc_trans
                      JOIN account a ON (acc_trans.chart_id = a.id)
                      WHERE a.accno = '-11111'
                      AND NOT cleared;
    SELECT results_eq('test',ARRAY[2],'1 Transactions closed');
    DEALLOCATE test;

    -- all items on account -11112 are part of the same payment AR payment,
    --   except a few GL items, some of which have the same source and transdate == payment_date
    --   and a few others which have the same source but transdate != payment_date
    PREPARE test AS SELECT reconciliation__new_report(test_get_account_id('-11112'), 100, now()::date, false,
        currval('workflow_seq')) > 0;
    SELECT results_eq('test',ARRAY[true],'1 Create Recon Report');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__pending_transactions(currval('cr_report_id_seq')::int, 110) > 0;
    SELECT results_eq('test',ARRAY[true],'1 Pending Transactions Ran');
    DEALLOCATE test;

    select is(
       ARRAY(SELECT our_balance FROM cr_report_line WHERE report_id = currval('cr_report_id_seq') order by our_balance),
       ARRAY[20, 90]::numeric[],
       'There are two recon lines; with balances [20 (gl), 90(payments)]'
       );

    PREPARE test AS SELECT count(distinct ac.trans_id)::int
                      FROM acc_trans ac
                      JOIN cr_report_line_links rll on ac.entry_id = rll.entry_id
                      JOIN cr_report_line rl ON rll.report_line_id = rl.id
                      WHERE report_id = currval('cr_report_id_seq')::int;
    SELECT results_eq('test',ARRAY[11],'Correct number of transactions 2');
    DEALLOCATE test;


    update gl set approved = true where id = -214;
    update acc_trans set approved = true
     where trans_id = -214
       and chart_id = test_get_account_id('-11112');

--    select reconciliation__pending_transactions

    PREPARE test AS SELECT reconciliation__pending_transactions(currval('cr_report_id_seq')::int, 110);
    SELECT results_eq('test',$$ SELECT id+3 FROM test_parameters $$,'1 Pending Transactions Ran');
    DEALLOCATE test;

    PREPARE test AS SELECT count(distinct ac.trans_id)::int
                      FROM acc_trans ac
                      JOIN cr_report_line_links rll on ac.entry_id = rll.entry_id
                      JOIN cr_report_line rl ON rll.report_line_id = rl.id
                      WHERE report_id = currval('cr_report_id_seq')::int;
    SELECT results_eq('test',ARRAY[12],'Correct number of transactions 3');
    DEALLOCATE test;

    PREPARE test AS SELECT count(*)::int
                      FROM cr_report_line
                      WHERE report_id = currval('cr_report_id_seq')::int;
    -- 1 payment, with GL adjustment and two GL lines with the same source (but different date) == 2
    SELECT results_eq('test',ARRAY[2],'1 Correct number of report lines');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__submit_set(currval('cr_report_id_seq')::int);
    SELECT results_eq('test',ARRAY[true],'1 Report Submitted');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__get_cleared_balance(test_get_account_id('-11112'));
    SELECT results_eq('test',ARRAY[-10]::numeric[],'1 Cleared balance pre-approval is 10');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__report_approve(currval('cr_report_id_seq')::int) > 0;
    SELECT results_eq('test',ARRAY[true],'1 Report Approved');
    DEALLOCATE test;

    PREPARE test AS SELECT count(*)::int
                      FROM acc_trans
                      JOIN account ON (acc_trans.chart_id = account.id)
                      WHERE accno = '-11112'
                      AND NOT cleared;
    SELECT results_eq('test',ARRAY[13],'1 Transactions open');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__get_cleared_balance(test_get_account_id('-11112')) = -10;
    SELECT results_eq('test',ARRAY[true],'1 Cleared balance post-approval is 10');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__new_report(test_get_account_id('-11112'), 100, now()::date, false,
        currval('workflow_seq'));
    SELECT results_eq('test',$$ SELECT id::bigint+4 FROM test_parameters $$,'1 Create Recon Report');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__pending_transactions(currval('cr_report_id_seq')::int, 110);
    SELECT results_eq('test',$$ SELECT id+4 FROM test_parameters $$,'1 Pending Transactions Ran');
    DEALLOCATE test;

    -- 1 payment, with GL adjustment and two GL lines with the same source (but different date) == 2
    PREPARE test AS SELECT count(*)::int
                      FROM cr_report_line
                      WHERE report_id = currval('cr_report_id_seq')::int;
    SELECT results_eq('test',ARRAY[2],'Correct number of report lines 4');
    DEALLOCATE test;

    PREPARE test AS SELECT count(distinct ac.trans_id)::int
                      FROM acc_trans ac
                      JOIN cr_report_line_links rll on ac.entry_id = rll.entry_id
                      JOIN cr_report_line rl ON rll.report_line_id = rl.id
                      WHERE report_id = currval('cr_report_id_seq')::int;
    -- 1 payment
    SELECT results_eq('test',ARRAY[12],'Correct number of transactions 4');
    DEALLOCATE test;


    select reconciliation__save_set(
           currval('cr_report_id_seq')::int,
           (select array_agg(id::int) from cr_report_line
             where report_id = currval('cr_report_id_seq')::int)
    );
    PREPARE test AS SELECT reconciliation__submit_set(currval('cr_report_id_seq')::int);
    SELECT results_eq('test',ARRAY[true],'Report Submitted');
    DEALLOCATE test;

    PREPARE test AS SELECT their_total::int
                      FROM reconciliation__report_summary(currval('cr_report_id_seq')::int);
    SELECT results_eq('test',ARRAY[110],'Their Balance Updated');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__get_cleared_balance(test_get_account_id('-11112'))= -10;
    SELECT results_eq('test',ARRAY[true],'Cleared balance pre-approval is 10');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__report_approve(currval('cr_report_id_seq')::int) > 0;
    SELECT results_eq('test',ARRAY[true],'Report Approved');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__delete_my_report(currval('cr_report_id_seq')::int) IS NULL;
    -- Should we thrown an exception?
    SELECT results_eq('test',ARRAY[true],'Cannot Delete Approved Recon Report');
    DEALLOCATE test;

    PREPARE test AS SELECT count(*)::int
                      FROM acc_trans
                      JOIN account a ON (acc_trans.chart_id = a.id)
                      WHERE accno = '-11112'
                      AND NOT cleared;
    SELECT results_eq('test',ARRAY[1],'Transactions closed');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__get_cleared_balance(test_get_account_id('-11112'));
    SELECT results_eq('test',ARRAY[-130.],'Cleared balance post-approval is 130');
    DEALLOCATE test;


    -- there are 3 items on account -11113, 2 are part of one payment each, the third is a GL transaction
    --   all have the same 'source' value, which means that the GL entry will be considered a correction
    --   to *both* payments. Because that's ambiguous, the GL item should be presented as a separate recon
    --   line instead.
    PREPARE test AS SELECT reconciliation__new_report(test_get_account_id('-11113'), 100, now()::date, false,
        currval('workflow_seq')) > 0;
    SELECT results_eq('test',ARRAY[true],'3 Create Recon Report');
    DEALLOCATE test;

    PREPARE test AS SELECT reconciliation__pending_transactions(currval('cr_report_id_seq')::int, 110) > 0;
    SELECT results_eq('test',ARRAY[true],'3 Pending Transactions Ran');
    DEALLOCATE test;



    -- Finish the tests and clean up.
    SELECT * FROM finish();

ROLLBACK;
