#!/usr/bin/perl
use strict;
use warnings;

use FindBin;
use lib "$FindBin::RealBin/../lib";

use Test::More tests => 27;
use Test::Exception;
use Bio::Chado::Schema;


my $schema = Bio::Chado::Schema::Test->init_schema();
my $cvterm_rs = $schema->resultset('Cv::Cvterm');

my $name = 'test cvterm_name';
my $cvname = 'test cv_name';

$schema->txn_do(sub {
    my $cvterm = $cvterm_rs->create_with({ name => $name, cv => $cvname });

    is( $cvterm->name, $name, 'cvterm_name test' );
    is( $cvterm->cv->name, $cvname, 'cv_name test');
    is( $cvterm->dbxref->accession, 'autocreated:' . $name, 'dbxref autocreated accession test' );
    is( $cvterm->dbxref->db->name, 'null', 'db name autocreated test' );

    #now add a synonym
    my $synonym='test synonym';
    my $type='exact';
    my $cvtermsynonym= $cvterm->add_synonym($synonym, { synonym_type=>$type, autocreate=>1 });

    is($cvtermsynonym->synonym, $synonym, "synonym test");
    is($cvtermsynonym->cvterm->name, $name, "synonym type test");
    is($cvtermsynonym->type->cv->name, 'synonym_type', "synonym cv name test");
    is($cvtermsynonym->type->dbxref->accession, $type, "synonym dbxref accession test");

    #try to store the same synonym - should pass since new synonyms are created after passing
    ##search_related with type_id and case-insensitive value

    my $existing_s = $cvterm->add_synonym($synonym, { synonym_type=>$type, autocreate=>1 });

    is($cvtermsynonym->cvtermsynonym_id() , $existing_s->cvtermsynonym_id(), "Existing synonym test");
    ##delete the synonym
    $cvterm->delete_synonym($synonym);

    is($cvterm->search_related('cvtermsynonyms', {synonym=>$synonym } )->count , 0, "deleted synonym test");

    #add a secondary dbxref
    my $sec_db = 'SEC';
    my $sec_acc= '1234';
    $cvterm->add_secondary_dbxref($sec_db.":".$sec_acc);

    my ($cvterm_dbxref)= $cvterm->get_secondary_dbxrefs;
    my ($re_db, $re_acc) = split(  ":" , $cvterm_dbxref);
    is($re_db, $sec_db, "secondary dbxref db name test");
    is($re_acc, $sec_acc, "secondary dbxref accession test");

    #and delete the secondary dbxref
    $cvterm->delete_secondary_dbxref($sec_db.":".$sec_acc);

    ($cvterm_dbxref)= $cvterm->get_secondary_dbxrefs;
    is($cvterm_dbxref, undef, "deleted secondary dbxref test");
    is($cvterm->search_related('cvterm_dbxrefs' )->count , 0, "deleted cvterm_dbxref test");

    #create new cvtermprop
    my $propname = "cvtermprop";
    my $value = "value 1";
    my $rank = 3;

    my $href = $cvterm->create_cvtermprops({ $propname => $value} , { autocreate => 1, allow_multiple_values => 1 , rank => $rank } );

    my $cvtermprop = $href->{$propname};
    is($cvtermprop->value(), $value, "cvtermprop value test");
    is($cvtermprop->rank() , $rank, "cvtermprop rank test");
    #

    #add another term
    my $child_name = 'test child term';
    my $child_term = $cvterm_rs->create_with({ name => $child_name, cv => $cvname });

    my $is_a = $cvterm_rs->create_with( { name => 'IS_A' , cv => 'relationship'} );
    $is_a->is_relationshiptype(1);
    $is_a->update;

    # create cvterm_relationship
    $cvterm->create_related('cvterm_relationship_objects', {
        subject_id => $child_term->cvterm_id,
        type_id => $is_a->cvterm_id,
                            } );

    # populate cvtermpath
    $child_term->create_related('cvtermpath_subjects', {
        object_id => $cvterm->cvterm_id,
        type_id => $is_a->cvterm_id,
        cv_id => $cvterm->cv_id,
        pathdistance => 1 });

    $cvterm->create_related('cvtermpath_subjects' , {
        object_id => $child_term->cvterm_id,
        type_id => $is_a->cvterm_id,
        cv_id => $cvterm->cv_id,
        pathdistance => -1 } );

    #and add a child to the child term
    my $grandchild_name = 'test grandchild term';
    my $grandchild_term = $cvterm_rs->create_with({ name => $grandchild_name, cv => $cvname });

    # create cvterm_relationship
    $child_term->create_related('cvterm_relationship_objects', {
        subject_id => $grandchild_term->cvterm_id,
        type_id => $is_a->cvterm_id,
                                } );

    # populate cvtermpath
    $grandchild_term->create_related('cvtermpath_subjects', {
        object_id => $child_term->cvterm_id,
        type_id => $is_a->cvterm_id,
        cv_id => $cvterm->cv_id,
        pathdistance => 1 });
    #########
    $grandchild_term->create_related('cvtermpath_subjects', {
        object_id => $cvterm->cvterm_id,
        type_id => $is_a->cvterm_id,
        cv_id => $cvterm->cv_id,
        pathdistance => 2 });
    #########
    $child_term->create_related('cvtermpath_subjects', {
        object_id => $grandchild_term->cvterm_id,
        type_id => $is_a->cvterm_id,
        cv_id => $cvterm->cv_id,
        pathdistance => -1 });

    #find the root.
    my $root_name = $name;
    my $root = $grandchild_term->root();
    is($root->name , $root_name , "cvterm  find root test");

    #find  children
    my $children_rs = $cvterm->children;
    my $child1 = $children_rs->first->find_related('subject', {});
    is ($child1->name , $child_name , 'cvterm find children test');
    is(scalar($children_rs->all) , 1 , 'Number of children test');

    # now using the cvtermpath
    my $direct_children = $cvterm->direct_children;
    is ($direct_children->first->name , $child_name , 'cvterm direct_children test');
    is(scalar($direct_children->all) , 1 , 'number of direct children');

    # find  parents
    my $parents_rs = $child_term->parents;
    my $parent1 = $parents_rs->first->find_related('object' , {} );
    is ($parent1->name , $name, 'cvterm find  parents test');
    is(scalar($parents_rs->all) , 1, 'Number of parents');
     # now using the cvtermpath
    my $direct_parents = $child_term->direct_parents;
    is ($direct_parents->first->name , $name , 'cvterm direct_parents test');
    is(scalar($direct_parents->all), 1, 'Number of direct parents');

    #find recursive children
    my @children = $cvterm->recursive_children->all;
    foreach my $ch (@children) { print "child =" .  $ch->name . "\n"; }
    is(scalar(@children) , 2, 'recursive_children test' );

    #find recursive parents
    my @parents = $grandchild_term->recursive_parents->all;
    foreach my $p (@parents ) { print "parent = " . $p->name . "\n"; }
    is(scalar(@parents) , 2, 'recursive_parents test');
    $schema->txn_rollback;
});


