import { environment } from 'enviroments/enviroments';
import { action, makeObservable, observable } from 'mobx';
import { loadable, loadableCard } from './Decorators/LoadingDecorator';
import { AssetsRecord, TypeTags } from 'types/default';
import { Entity, EntityStore } from './EntityStore';
import { RootStore } from './RootStore';
import { TPostOs } from '../pages/AssetsDashboard/AssetsCardInfo/types';
import { Asset, AssetPatch, TOsList } from '../pages/AssetsDashboard/types';
import FileDownload from '../services/FileDownload';
import request from 'services/request';

type ListRecord = AssetsRecord;

export class Assets extends Entity {
  @observable private listRecord: ListRecord;

  constructor(id: string, listRecord: ListRecord) {
    super(id);
    this.listRecord = listRecord;
  }

  get _listRecord(): any {
    return this.listRecord;
  }

  @action
  setListRecord = (value: ListRecord): void => {
    this.listRecord = value;
  };
}

export class AssetsStore extends EntityStore<Assets> {
  @observable osList: TOsList[] = [];

  @observable tagsList: TypeTags[] = [];

  @observable manufacturers = [];

  @observable selectedAsset: Asset | null | undefined = null;

  nextAssetsList: any;

  previousAssetsList: any;

  constructor(private readonly rootStore: RootStore) {
    super();
    makeObservable(this);
  }

  get _osList(): any {
    return this.osList;
  }

  @action
  setOsList = (value: any): void => {
    this.osList = value;
  };

  @action
  setSelectedAsset = (value: null | undefined | Asset): void => {
    switch (value) {
      case undefined:
        this.selectedAsset = {
          asset_type: '',
          description: null,
          group: null,
          incidents: [],
          ip: '',
          mac: null,
          manufacturer: null,
          model: null,
          name: '',
          os: null,
          ports: null,
          sensor: null,
          status: 0,
          updated: '',
          vulnerabilities: 0,
        };
        break;

      case null:
        this.selectedAsset = null;
        break;

      default:
        this.selectedAsset = value;
        break;
    }
  };

  @action
  setManufacturersList = (value: any): void => {
    this.manufacturers = value;
  };

  @action
  setTagsList = (value: any): void => {
    this.tagsList = value;
  };

  @loadable
  async fetchAssetsList(
    page: number,
    pageSize: number,
    sorter: string,
  ): Promise<void> {
    await request({
      method: 'get',
      url:
        page && pageSize
          ? `${environment.endPoints.assets.elements}?page=${page}&page_size=${pageSize}${sorter}`
          : `${environment.endPoints.assets.elements}`,
    }).then(
      action((response) => {
        this.entities.clear();
        for (const item of response.data.results) {
          const asset = new Assets(`${item.id}`, item);
          asset.setListRecord(item);
          this.nextAssetsList = response.data.next;
          this.previousAssetsList = response.data.previous;
          this.entities.set(String(item.id), asset);
        }
        this.setTotal(response.data.count);
      }),
    );
  }

  @loadable
  async patchAssetsRecord(id: string, data: AssetPatch): Promise<void> {
    await request({
      method: 'patch',
      url: `${environment.endPoints.assets.elements}${id}/`,
      data,
    }).then(
      action((response) => {
        const oldRecord = this.record(String(response.data.id))._listRecord;
        for (const oldRecordKey in oldRecord) {
          if (oldRecordKey === 'incidents') {
            oldRecord[oldRecordKey] = response.data[oldRecordKey].length;
          } else oldRecord[oldRecordKey] = response.data[oldRecordKey];
        }
        const asset = new Assets(String(response.data.id), oldRecord);
        this.entities.set(String(String(response.data.id)) as any, asset);
        this.selectedAsset = null;
      }),
    );
  }

  fetchManufacturerList(page: number): void {
    request({
      method: 'get',
      url: page
        ? `${environment.endPoints.assets.manufacturer}?page=${page}`
        : `${environment.endPoints.assets.manufacturer}`,
    }).then(
      action((response) => {
        this.setManufacturersList(response.data.results);
      }),
    );
  }

  @loadableCard
  async fetchAssetRecord(id = 1): Promise<void> {
    await request({
      method: 'get',
      url: `${environment.endPoints.assets.elements}${id}/`,
    }).then(
      action((response) => {
        this.selectedAsset = response.data;
      }),
    );
  }

  @loadable
  changeStatusAssetsRecs(mas: number[]): void {
    request({
      method: 'post',
      url: `${environment.endPoints.assets.authorize}`,
      data: { selected_assets: mas },
    }).then(
      action(() => {
        for (let i = 0; i < mas.length; i++) {
          const assetObj = this.record(String(mas[i]))?._listRecord;
          if (assetObj) {
            assetObj.status = 1;
            const asset = new Assets(String(mas[i]), assetObj);
            this.entities.set(String(mas[i]) as any, asset);
          }
        }
      }),
    );
  }

  @loadable
  fetchOSList(): void {
    request({
      method: 'get',
      url: `${environment.endPoints.assets.osList}`,
    }).then(
      action((response) => {
        this.setOsList(response.data.results);
      }),
    );
  }

  @loadable
  postOSList(data: TPostOs): void {
    request({
      method: 'post',
      url: `${environment.endPoints.assets.osList}`,
      data,
    }).then(
      action((response) => {
        return this.osList.push(response.data);
      }),
    );
  }

  async exportCSV(): Promise<any> {
    return request({
      method: 'get',
      url: `${environment.endPoints.assets.exportsCSV}`,
      responseType: 'blob',
    }).then((res: any) => {
      const regexp = /"(.*?)"/;
      const filename = res.headers['content-disposition'].match(regexp)[1];
      FileDownload(res.data, filename);
    });
  }

  @loadable async deleteAssetsRecord(id: number[]): Promise<void> {
    const myPromise = (idd: number): Promise<number> => {
      return new Promise((resolve, reject) => {
        return request({
          method: 'delete',
          url: `${environment.endPoints.assets.elements}${idd}/`,
        })
          .then(() => resolve(idd))
          .catch(() => reject(id));
      });
    };

    const mas = id.map((item) => {
      return myPromise(item);
    });

    await Promise.allSettled(mas);
  }
}
