/*
 * Copyright (C) 2023 StApps
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */
/* eslint-disable @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-explicit-any, unicorn/no-thenable */
import {TestBed} from '@angular/core/testing';
import {DaiaDataProvider} from './daia-data.provider';
import {HebisModule} from './hebis.module';
import {ConfigProvider} from '../config/config.provider';
import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider';
import {StorageProvider} from '../storage/storage.provider';
import {LoggerTestingModule} from 'ngx-logger/testing';
import {MapModule} from '../map/map.module';
import {provideHttpClient, withInterceptorsFromDi} from '@angular/common/http';
import {StorageModule} from '../storage/storage.module';
import {DaiaHolding, DaiaService} from './protocol/response';
import {Observable, of} from 'rxjs';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';

const translations: any = {data: {detail: {TITLE: 'Foo'}}};

class TranslateFakeLoader implements TranslateLoader {
  getTranslation(_lang: string): Observable<any> {
    return of(translations);
  }
}

describe('DaiaDataProvider', () => {
  let daiaDataProvider: DaiaDataProvider;
  let configProvider: ConfigProvider;
  const proxyUrl = 'https://some-proxy.com?q=';
  const getProxifiedUrl = (url: string) => `${proxyUrl}${encodeURIComponent(url)}`;

  beforeEach(async () => {
    configProvider = jasmine.createSpyObj('ConfigProvider', ['getValue']);
    TestBed.configureTestingModule({
      imports: [
        HebisModule,
        MapModule,
        StorageModule,
        LoggerTestingModule,
        TranslateModule.forRoot({
          loader: {provide: TranslateLoader, useClass: TranslateFakeLoader},
        }),
      ],
      providers: [
        {
          provide: ConfigProvider,
          useValue: configProvider,
        },
        StAppsWebHttpClient,
        StorageProvider,
        DaiaDataProvider,
        provideHttpClient(withInterceptorsFromDi()),
      ],
    });
    daiaDataProvider = TestBed.inject(DaiaDataProvider);
    daiaDataProvider.hebisProxyUrl = proxyUrl;
  });
  describe('getResourceLink', () => {
    it('should return link with proxy when open property is undefined', () => {
      const available: DaiaService = {
        delay: '',
        expected: '',
        href: 'https://some-url.com',
        limitations: [],
        service: 'presentation',
      };
      const holding: DaiaHolding = {
        department: {id: '', content: ''},
        id: '',
        online: false,
        signature: '',
        available: available,
      };

      expect(daiaDataProvider.getHoldingLink(holding, holding.open)).toEqual(
        getProxifiedUrl(available.href as string),
      );
    });

    it('should return the resource link without proxy when the resource is open', () => {
      const available: DaiaService = {
        delay: '',
        expected: '',
        href: 'https://some-url.com',
        limitations: [],
        service: 'other',
      };
      const holding: DaiaHolding = {
        department: {id: '', content: ''},
        id: '',
        online: false,
        open: true,
        signature: '',
        available: available,
      };

      expect(daiaDataProvider.getHoldingLink(holding, holding.open)).toEqual(available.href as string);
    });

    it('should return the resource link with proxy when the resource is not open', () => {
      const available: DaiaService = {
        delay: '',
        expected: '',
        href: 'https://some-url.com',
        limitations: [],
        service: 'other',
      };
      const holding: DaiaHolding = {
        department: {id: '', content: ''},
        id: '',
        online: false,
        open: false,
        signature: '',
        available: available,
      };

      expect(daiaDataProvider.getHoldingLink(holding, holding.open)).toEqual(
        getProxifiedUrl(available.href as string),
      );
    });
  });

  describe('getResourceStatus', () => {
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    // let available, unavalable: SCDaiaService[];

    const checkedOut: DaiaService = {
      expected: '2022-09-01',
      limitations: [],
      service: 'loan',
    };

    const notYetAvailableOnBuy: DaiaService = {
      limitations: [{id: 'OnBuy', content: ''}],
      service: 'loan',
    };

    const notYetAvailableJustReturned: DaiaService = {
      limitations: [{id: 'JustReturned', content: ''}],
      service: 'loan',
    };

    const notAvailableCopyIsMissing: DaiaService = {
      limitations: [{id: 'CopyIsMissing', content: ''}],
      service: 'loan',
    };

    const notAvailableCanceled: DaiaService = {
      limitations: [{id: 'Canceled', content: ''}],
      service: 'loan',
    };

    const libraryOnlyOnlyInHouse: DaiaService = {
      limitations: [{id: 'OnlyInHouse', content: ''}],
      service: 'loan',
    };

    const libraryOnlyExternalLoan: DaiaService = {
      limitations: [{id: 'ExternalLoan', content: ''}],
      service: 'loan',
    };

    const libraryOnlyPresentation: DaiaService = {
      service: 'presentation',
    };

    const availableLimitationsUndefined: DaiaService = {
      service: 'loan',
    };

    const availableLimitationsEmpty: DaiaService = {
      limitations: [],
      service: 'loan',
    };

    it('should return check out', () => {
      expect(daiaDataProvider.getHoldingStatus([], [checkedOut])).toEqual('checked_out');
    });

    it('should return not yet available', () => {
      expect(daiaDataProvider.getHoldingStatus([], [notYetAvailableOnBuy])).toEqual('not_yet_available');
      expect(daiaDataProvider.getHoldingStatus([], [notYetAvailableJustReturned])).toEqual(
        'not_yet_available',
      );
    });

    it('should return not available', () => {
      expect(daiaDataProvider.getHoldingStatus([], [notAvailableCopyIsMissing])).toEqual('not_available');
      expect(daiaDataProvider.getHoldingStatus([], [notAvailableCanceled])).toEqual('not_available');
    });

    it('should return library only', () => {
      expect(daiaDataProvider.getHoldingStatus([], [libraryOnlyOnlyInHouse])).toEqual('library_only');
      expect(daiaDataProvider.getHoldingStatus([libraryOnlyExternalLoan], [])).toEqual('library_only');
      expect(daiaDataProvider.getHoldingStatus([libraryOnlyPresentation], [])).toEqual('library_only');
    });

    it('should return available', () => {
      expect(
        daiaDataProvider.getHoldingStatus([availableLimitationsUndefined, libraryOnlyPresentation], []),
      ).toEqual('available');
      expect(
        daiaDataProvider.getHoldingStatus([availableLimitationsEmpty, libraryOnlyPresentation], []),
      ).toEqual('available');
    });

    it('should return unknown otherwise', () => {
      const withoutLoan: DaiaService = {
        limitations: [],
        service: 'anything else',
      };

      expect(daiaDataProvider.getHoldingStatus([withoutLoan], [])).toEqual('unknown');
      expect(daiaDataProvider.getHoldingStatus([], [withoutLoan])).toEqual('unknown');
      expect(daiaDataProvider.getHoldingStatus([], [availableLimitationsUndefined])).toEqual('unknown');
      expect(daiaDataProvider.getHoldingStatus([], [availableLimitationsEmpty])).toEqual('unknown');
    });
  });
});
