import gql from 'graphql-tag'

import { create, error, ReferenceMap, Scene } from '@hatiolab/things-scene'
import { BoardDataStorage } from '@operato/board'
import { client, gqlContext, subscribe } from '@operato/graphql'

export function createBoardProvider() {
  var _provider = new ReferenceMap<Scene>(
    async (boardId, resolve, reject): Promise<any> => {
      try {
        const response = await client.query({
          query: gql`
            query FetchBoardById($id: String!) {
              board(id: $id) {
                model
              }
            }
          `,
          variables: { id: boardId },
          context: gqlContext()
        })

        const board = response.data?.board

        if (!board) {
          reject(new Error('Failed to get the requested board.'))
          return
        }

        var model = JSON.parse(board.model)

        var scene: Scene

        try {
          scene = await provider.get(boardId)
          console.warn('Board fetched more than twice.', boardId)
        } catch (e) {
          scene = create({
            model,
            mode: 0,
            refProvider: provider as any,
            dataStorage: new BoardDataStorage(boardId),
            dataSubscriptionProvider: {
              subscribe: async (tag, component) => {
                return await subscribe(
                  {
                    query: gql`
                              subscription {
                                data(tag: "${tag}") {
                                  tag
                                  data
                                }
                              }
                            `
                  },
                  {
                    next: async ({ data }) => {
                      if (data) {
                        component.data = data.data.data
                      }
                    }
                  }
                )
              },

              dispose() {}
            }
          })

          // s.app.baseUrl = undefined;
        }

        resolve(scene)

        // resolve(scene, {
        //   ...board,
        //   model
        // })
      } catch (e) {
        error(e)
        reject(e)
      }
    },
    async (id, ref) => {
      ref.dispose()
    }
  )

  return _provider
}

export const provider = createBoardProvider()
