import 'rxjs'
import assert from 'assert'
import { make, invalidate, query } from '../../src/graph';
import { Expire, available } from '../../src/cache/strategies';
import Node from './Node'

const state = {
  foo: null,
  slaveFetchCount: null
}

const MASTER_EXPIRE_TIME = 100;

const makeTestGraph = () => {
  const master = Node({
    id: 'master',
    strategy: new Expire(MASTER_EXPIRE_TIME),
    params: { token: 'token' },
    fetch: () => Promise.resolve({ bar: { foo: state.foo } })
  });
  const slave = Node({
    id: 'slave',
    strategy: available,
    dependencies: {
      master: { query: master }
    },
    fetch: ({ master: { bar } }) => {
      state.slaveFetchCount = state.slaveFetchCount + 1;
      return Promise.resolve(bar);
    }
  })

  return make({ ...master, ...slave });
}

describe('graph/deps', () => {

  it('"slave" should be re-fetched if "master" changes and is being observed', (done) => {
    const graph = makeTestGraph()

    state.foo = 'foo_1';
    state.slaveFetchCount = 0;

    const slave = query(graph, ['slave'], { token: 'token' })

    slave.subscribe(() => {}); // add a subscriber to "slave"

    // invalidate "master" after its cache has already expired
    setTimeout(() => {
      state.foo = 'foo_2';
      invalidate(graph, ['master'], { token: 'token' }) // invalidate later on

      // verify that "slave" has been correctly re-fetched
      setTimeout(() => {
        slave.subscribe((r) => {
          assert.equal(r.data.slave.data.foo, 'foo_2');
          assert.equal(state.slaveFetchCount, 2);
          done();
        });
      }, MASTER_EXPIRE_TIME * 2)
    }, MASTER_EXPIRE_TIME * 2);

  });

  it('"slave" should not be re-fetched if "master" changes but is not being observed', (done) => {
    const graph = makeTestGraph()

    state.foo = 'foo_1';
    state.slaveFetchCount = 0;

    const master = query(graph, ['master'], { token: 'token' });
    query(graph, ['slave'], { token: 'token' });

    master.subscribe(() => {}); // add a subscriber to "master"

    // invalidate "master" after its cache has already expired
    setTimeout(() => {
      state.foo = 'foo_2';
      invalidate(graph, ['master'], { token: 'token' }) // invalidate later on

      // verify that "slave" has been correctly re-fetched
      setTimeout(() => {
        assert(state.slaveFetchCount, 0);
        done();
      }, MASTER_EXPIRE_TIME * 2)
    }, MASTER_EXPIRE_TIME * 2);

  });

});

@@ -905,36 +905,32 @@
 ing observed', (
-done
 ) =%3E %7B%0A    const
@@ -1138,16 +1138,64 @@
 slave%22%0A%0A
+    return new Promise((resolve, reject) =%3E %7B%0A  
     // i
@@ -1245,32 +1245,34 @@
 ady expired%0A    
+  
 setTimeout(() =%3E
@@ -1266,32 +1266,34 @@
 Timeout(() =%3E %7B%0A
+  
       state.foo 
@@ -1301,32 +1301,34 @@
  'foo_2';%0A      
+ 
+ 
 invalidate(graph
@@ -1383,32 +1383,34 @@
 later on%0A%0A      
+  
 // verify that %22
@@ -1438,32 +1438,34 @@
 ctly re-fetched%0A
+  
       setTimeout
@@ -1477,24 +1477,26 @@
 %3E %7B%0A        
+  
 slave.subscr
@@ -1504,24 +1504,46 @@
 be((r) =%3E %7B%0A
+            try %7B%0A    
           as
@@ -1588,32 +1588,36 @@
 _2');%0A          
+  
+  
 assert.equal(sta
@@ -1646,32 +1646,105 @@
 ;%0A          
-don
+    resolv
 e();%0A
+            %7D catch (e) %7B%0A              reject(e)%0A            %7D%0A  
         %7D);%0A
@@ -1741,32 +1741,34 @@
       %7D);%0A      
+  
 %7D, MASTER_EXPIRE
@@ -1770,32 +1770,34 @@
 XPIRE_TIME * 2)%0A
+  
     %7D, MASTER_EX
@@ -1803,32 +1803,39 @@
 XPIRE_TIME * 2);
+%0A    %7D)
 %0A%0A  %7D);%0A%0A  it('%22
@@ -1915,20 +1915,16 @@
 rved', (
-done
 ) =%3E %7B%0A 
@@ -2194,16 +2194,64 @@
 aster%22%0A%0A
+    return new Promise((resolve, reject) =%3E %7B%0A  
     // i
@@ -2305,24 +2305,26 @@
 expired%0A    
+  
 setTimeout((
@@ -2326,24 +2326,26 @@
 out(() =%3E %7B%0A
+  
       state.
@@ -2361,24 +2361,26 @@
 o_2';%0A      
+ 
+ 
 invalidate(g
@@ -2437,24 +2437,26 @@
 e later on%0A%0A
+  
       // ver
@@ -2500,32 +2500,34 @@
 e-fetched%0A      
+  
 setTimeout(() =%3E
@@ -2521,32 +2521,52 @@
 Timeout(() =%3E %7B%0A
+          try %7B%0A    
         assert(s
@@ -2603,16 +2603,83 @@
     
-don
+    resolv
 e();%0A
+          %7D catch (e) %7B%0A            reject(e)%0A          %7D%0A  
     
@@ -2703,24 +2703,26 @@
 E_TIME * 2)%0A
+  
     %7D, MASTE
@@ -2741,16 +2741,23 @@
 E * 2);%0A
+    %7D);
 %0A  %7D);%0A%0A

async tests should return a Promise