import { Injectable, Provider } from '@angular/core';
import { Observable } from 'rxjs';
import { Apollo, gql } from 'apollo-angular';
import { catchError, map } from 'rxjs/operators';
import { SpinnerService } from 'src/app/service/spinner.service';
import { Setting } from 'src/app/model/entities/setting';

@Injectable()
export class SettingsDataService {
  constructor(
    private spinner: SpinnerService,
    private apollo: Apollo
  ) {}

  load(): Observable<Setting[]> {
    return this.apollo
      .query<{ settings: Setting[] }>({
        query: gql`
          query GetSettings {
            settings {
              key
              value
            }
          }
        `,
        variables: {},
      })
      .pipe(
        catchError(err => {
          this.spinner.hide();
          throw err;
        })
      )
      .pipe(map(result => result.data.settings));
  }

  loadByKey(key: string): Observable<Setting> {
    return this.apollo
      .query<{ settings: Setting[] }>({
        query: gql`
          query getSetting($key: String!) {
            settings(key: $key) {
              key
              value
            }
          }
        `,
        variables: {
          key,
        },
      })
      .pipe(
        catchError(err => {
          this.spinner.hide();
          throw err;
        })
      )
      .pipe(map(result => result.data.settings[0]));
  }

  onUpdate(): Observable<void> {
    return this.apollo
      .subscribe<{ settingChange: void }>({
        query: gql`
          subscription onSettingChange {
            settingChange
          }
        `,
      })
      .pipe(map(result => result.data?.settingChange));
  }

  change(object: Setting): Observable<Setting | undefined> {
    return this.apollo
      .mutate<{ setting: { change: Setting } }>({
        mutation: gql`
          mutation changeSetting($input: SettingInput!) {
            setting {
              change(input: $input) {
                key
                value
              }
            }
          }
        `,
        variables: {
          input: {
            key: object.key,
            value: object.value,
          },
        },
      })
      .pipe(
        catchError(err => {
          this.spinner.hide();
          throw err;
        })
      )
      .pipe(map(result => result.data?.setting.change));
  }

  static provide(): Provider[] {
    return [SettingsDataService];
  }
}
