import { Injectable, Injector, OnDestroy } from '@angular/core';
import UrlPattern from 'url-pattern';
import { MOCK_CONFIG } from './mock-config.token';
import { IMockCollect, IMockConfig, ISafeAny, REQUEST_METHOD } from './mock.type';

@Injectable({ providedIn: 'root' })
export class MockService implements OnDestroy {
  private collect: IMockCollect[] = [];
  readonly config: IMockConfig;
  constructor(private injector: Injector) {
    this.config = this.injector.get(MOCK_CONFIG);
    try {
      this.collectMock();
    } catch (e) {
      throw e;
    }
  }

  private collectMock() {
    const data: ISafeAny = this.config.data;
    if (!data) return;
    // 各种容错处理
    Object.keys(data).forEach((moduleKey: string) => {
      const rulegroups = data[moduleKey];
      if (!rulegroups) return;
      Object.keys(rulegroups).forEach((apiKey: string) => {
        const value = rulegroups[apiKey];
        const patterns = this.genPattern(moduleKey, apiKey, value);
        Array.from(patterns, (pattern) => {
          // 保证接口唯一性
          const item = this.collect.find((col) => {
            return col.url === pattern.url && col.method === pattern.method;
          });
          if (item) {
            item.value = pattern.value;
          } else {
            this.collect.push(pattern);
          }
        });
      });
    });

    this.collect.sort((a, b) => (b.url || '').toString().length - (a.url || '').toString().length);
  }

  private genPattern(mdl: string, rule: string, value: ISafeAny): IMockCollect[] {
    let method = 'GET';
    const url = rule;
    if (typeof value === 'function') {
      return [{
        url,
        method,
        pattern: new UrlPattern(url),
        value: {
          value
        }
      }];
    } else {
      return Object.keys(value).map(mtd => {
        method = mtd.toUpperCase();
        if (!REQUEST_METHOD.includes(method)) {
          method = 'GET';
          console.warn(`[@bixi/mock]${mdl}-${url}-${mtd} 请求类型配置错误，请查看`);
        }
        return {
          url,
          value: value[mtd], // function or object
          method,
          pattern: new UrlPattern(url)
        };
      });
    }
  }

  getCollect(method: string, url: string): IMockCollect | null {
    method = method.toUpperCase() || 'GET';
    const urlParams = url.split('?');
    const ruleStr = urlParams[0];
    const paramString = urlParams[1] || '';

    const list = this.collect.filter(w => w.method === method && w.pattern.match(ruleStr));
    if (list.length === 0) return null;
    const ret = list.find(w => w.url === ruleStr) || list[0];
    return {
      ...ret,
      params: ret.pattern.match(ruleStr),
      query: this.getQuery(paramString)
    };
  }



  private getQuery(url: string) {
    const result: {
      [key: string]: string;
    } = {};
    if (!url) return result;
    url.split('&').forEach((query) => {
      const querySplit = query.split('=');
      result[querySplit[0]] = querySplit[1];
    });
    return result;
  }

  clearCollect() {
    this.collect = [];
  }

  get collects() {
    return this.collect;
  }

  ngOnDestroy(): void {
    this.clearCollect();
  }
}
