import { Injectable } from '@angular/core';
import {
  Observable,
  of as observableOf,
} from 'rxjs';
import {
  map,
  take,
} from 'rxjs/operators';

import { ConfigurationDataService } from '../core/data/configuration-data.service';
import { RemoteData } from '../core/data/remote-data';
import { ConfigurationProperty } from '../core/shared/configuration-property.model';
import { getFirstCompletedRemoteData } from '../core/shared/operators';
import {
  hasNoValue,
  isEmpty,
} from './empty.util';

export const CANONICAL_PREFIX_KEY = 'handle.canonical.prefix';

const PREFIX_REGEX = (prefix: string | undefined) => {
  const formattedPrefix: string = prefix?.replace(/\/$/, '');
  return new RegExp(`(${formattedPrefix ? formattedPrefix  + '|' : '' }handle)\/([^\/]+\/[^\/]+)$`);
};
const NO_PREFIX_REGEX = /^([^\/]+\/[^\/]+)$/;

@Injectable({
  providedIn: 'root',
})
export class HandleService {

  constructor(
    protected configurationService: ConfigurationDataService,
  ) {
  }

  /**
   * Turns a handle string into the default 123456789/12345 format
   *
   * When the <b>handle.canonical.prefix</b> doesn't end with handle, be sure to expose the variable so that the
   * frontend can find the handle
   *
   * @param handle the input handle
   * @return
   * <ul>
   *   <li>normalizeHandle('123456789/123456')                                 // '123456789/123456'</li>
   *   <li>normalizeHandle('12.3456.789/123456')                               // '12.3456.789/123456'</li>
   *   <li>normalizeHandle('https://hdl.handle.net/123456789/123456')          // '123456789/123456'</li>
   *   <li>normalizeHandle('https://rest.api/server/handle/123456789/123456')  // '123456789/123456'</li>
   *   <li>normalizeHandle('https://rest.api/server/handle/123456789')         // null</li>
   * </ul>
   */
  normalizeHandle(handle: string): Observable<string | null> {
    if (hasNoValue(handle)) {
      return observableOf(null);
    }
    return this.configurationService.findByPropertyName(CANONICAL_PREFIX_KEY).pipe(
      getFirstCompletedRemoteData(),
      map((configurationPropertyRD: RemoteData<ConfigurationProperty>) => {
        if (configurationPropertyRD.hasSucceeded) {
          return configurationPropertyRD.payload.values.length >= 1 ? configurationPropertyRD.payload.values[0] : undefined;
        } else {
          return undefined;
        }
      }),
      map((prefix: string | undefined) => {
        let matches: string[];

        matches = handle.match(PREFIX_REGEX(prefix));

        if (isEmpty(matches) || matches.length < 3) {
          matches = handle.match(NO_PREFIX_REGEX);
        }

        if (isEmpty(matches) || matches.length < 2) {
          return null;
        } else {
          return matches[matches.length - 1];
        }
      }),
      take(1),
    );
  }

}