import { GlobalLoaderService } from './../../resources/global-loader/global-loader-service';
import { BaseEntityWithId } from './../../model/common-model';
import { IMenuItem } from './../../ui/menu/ui-menus';

import { autoinject } from 'aurelia-framework';
import { HttpClient, json } from 'aurelia-fetch-client';

//export type ImportContextName = "metering" | "item" | "thirdParty";

export interface ValidateConfigResponse {
  isValid: boolean;
  errors: InputFieldError[];
}
export interface InputFieldError {
  fieldName: string;
  error: string;
}

export interface ImportRowError {
  propertyName: string;
  error: string;
  errorTranslationkey?: string;
  errorValue?: string;
}
export interface ImportRow {
  id: number;

  lineNr: number;
  isValid: boolean;
  serverErrors: ImportRowError[];
  actions?: ImportRowAction[];
  ignoreRow: boolean | null;

  edit?: boolean;
  menu?: IMenuItem[];
}
export interface ImportRowAction {
  actionId: number;
  labelTranslationKey: string;
  icon: string;
}
export interface ImportRowPatch {
  propertyName: string;
  propertyValue: string;
}
export interface ImportRowBatchPatch extends ImportRowPatch {
  importRowIdToUpdate: number[];
  saveAlias: boolean | null;
  oldValue: string | null;
}
export interface ImportResults {
  isFileValid: boolean;
  resultFileUri: string;
  linesTreatedCount: number;
  linesCount: number;
  linesImportedCount: number;
  importError: string;
}
@autoinject
export class ImportService {

  url: string = "/api/import/";

  constructor(private httpClient: HttpClient, private globalLoader: GlobalLoaderService) {
  }

  public async startSession(context: string, customParameter: number): Promise<ImportSession> {
    const startResult = await this.httpClient.put(this.url + "?" + new URLSearchParams({
      context: context,
      customParameter: customParameter?.toString() ?? '0'
    }));
    if (startResult.ok) {
      const session = await startResult.json();
      return session;
    }
    return null;
  }

  public async getSession(sessionId: number): Promise<ImportSession> {
    const sessionResult = await this.httpClient.get(this.url + sessionId.toString());
    if (sessionResult.ok) {
      const session = await sessionResult.json();
      return session;
    }
    return null;
  }

  public async saveFileSession(id: number, fileSessions: ImportFileSessions, context: string) {
    const saveResult = await this.httpClient.post(this.url + id + "/saveFile/" + context, JSON.stringify(fileSessions));
    if (saveResult.ok) {
    }
    return null;
  }

  public async saveSession(session: ImportSession) {
    const saveResult = await this.httpClient.post(this.url, JSON.stringify(session));
    if (saveResult.ok) {
    }
    return null;
  }

  async getColumnMapping(id: number): Promise<Array<ImportColumnMapping>> {
    const mappingResult = await this.httpClient.get(this.url + id + '/mapping');
    if (mappingResult) {
      const mapping = await mappingResult.json();
      return mapping;
    }
    return null;
  }

  async getSheetDtos(id: number): Promise<Array<SheetDTO>> {
    const sheetsResult = await this.httpClient.get(this.url + id + '/sheets');
    if (sheetsResult) {
      const sheets = await sheetsResult.json();
      return sheets;
    }
    return null;
  }
  async getHeaderLabel(id: number): Promise<Array<HeaderLabel>> {
    const headerResult = await this.httpClient.get(this.url + id + '/labels');
    if (headerResult) {
      const header = await headerResult.json();
      return header;
    }
    return null;
  }

  async saveMapping(id: number, columnsMapping: ImportColumnMapping[]) {
    //To fix bug ui-select in ui-select-footer
    columnsMapping.forEach(x => {
      if (x.columnEndIndex == "''" || x.columnEndIndex == null) {
        x.columnEndIndex = null;
      } else {
        x.columnEndIndex = parseInt(x.columnEndIndex.toString());
      }
    });
    const param = {
      ImportColumnMappings: columnsMapping
    }
    const saveMappingResult = await this.httpClient.post(this.url + id + "/mapping", JSON.stringify(param));
    if (saveMappingResult.ok) {
    } else {
      throw "Exception save mapping";
    }
    return null;
  }
  async saveConfig(context: string, id: number, config: any) {
    const saveMappingResult = await this.httpClient.post(this.url + context + "/" + id + "/config", JSON.stringify(config));
    if (saveMappingResult.ok) {
    } else {
      throw "Exception saving config";
    }
    return null;
  }
  async validateConfig(context: string, id: number, mapping: ImportColumnMapping[], config: any): Promise<ValidateConfigResponse> {
    mapping.forEach(x => {
      if (x.columnEndIndex == "''" || x.columnEndIndex == null) {
        x.columnEndIndex = null;
      } else {
        x.columnEndIndex = parseInt(x.columnEndIndex.toString());
      }
    });

    const validateMappingResult = await this.httpClient.post(this.url + context + "/" + id + "/config/validate", JSON.stringify({ importColumnMappings: mapping, "config": config }));
    if (validateMappingResult.ok) {
      return await validateMappingResult.json();
    } else {
      throw "Exception saving config";
    }
  }

  async getErrors(context: string, id: number): Promise<ImportRow[]> {
    this.globalLoader.allow(true, 0);
    const errorsResult = await this.httpClient.get(this.url + context + "/" + id + '/has-errors');
    if (errorsResult) {
      const errors = await errorsResult.json();
      return errors;
    }
    return null;
  }
  async saveImportRowProperty(context: string, sessionId: number, id: number, propertyName: string, n: any): Promise<ImportRow> {
    this.globalLoader.allow(true, 0);
    let requestUri = this.url + context + "/" + sessionId + '/row/' + id;
    const patchDoc: ImportRowPatch = {
      propertyName: propertyName,
      propertyValue: n
    }
    let patchResponse = await this.httpClient.patch(requestUri, JSON.stringify(patchDoc));
    if (patchResponse.ok) {
      return await patchResponse.json();
    } else {
      if (patchResponse.status == 400) {
        let text = await patchResponse.text();
        throw text;
      }
    }
  }
  async saveImportRowBatch(context: string, sessionId: number, ids: number[], propertyName: string, n: any, saveAlias: boolean = false, oldValue: string = null): Promise<ImportRow[]> {
    this.globalLoader.allow(true, 0);
    let requestUri = this.url + context + "/" + sessionId + '/batch-update';
    const patchDoc: ImportRowBatchPatch = {
      propertyName: propertyName,
      propertyValue: n,
      importRowIdToUpdate: ids,
      saveAlias: saveAlias,
      oldValue: oldValue
    }
    let patchResponse = await this.httpClient.patch(requestUri, JSON.stringify(patchDoc));
    if (patchResponse.ok) {
      return await patchResponse.json();
    } else {
      if (patchResponse.status == 400) {
        let text = await patchResponse.text();
        throw text;
      }
    }
  }
  async executeAction(context: string, sessionId: number, id: number, actionId: number): Promise<ImportRow> {
    let requestUri = this.url + context + "/" + sessionId + '/row/' + id + '/action/' + actionId;
    let patchResponse = await this.httpClient.post(requestUri);
    if (patchResponse.ok) {
      return await patchResponse.json();
    } else {
      if (patchResponse.status == 400) {
        throw await patchResponse.text();
      }
    }
  }
  async getPossibleValues(context: string, sessionId: number, propertyName: string): Promise<string[]> {
    let requestUri = this.url + context + "/" + sessionId + '/possible-values/' + propertyName;
    let patchResponse = await this.httpClient.get(requestUri);
    if (patchResponse.ok) {
      return await patchResponse.json();
    } else {
      if (patchResponse.status == 400) {
        let text = await patchResponse.text();
        throw text;
      }
    }
  }
  async process(context: string, id: number): Promise<ImportResults> {
    this.globalLoader.allow(true, 0);
    const processResult = await this.httpClient.post(this.url + context + "/" + id + "/process");
    if (processResult.ok) {
      return await processResult.json();
    } else {
      throw "Exception saving config";
    }
    return null;
  }
}


export interface ImportFileSessions extends BaseEntityWithId {
  fileUri: string;
  fileName: string;
}
export interface ImportSession extends BaseEntityWithId {
  importFileSessionsId: number;
  importFileSessions: ImportFileSessions;
  headerLineRowNumber: number;
  firstDataLineRowNumber: number;
  sheetsIndex: number[];

  resultFileUri: string;

  linesTreatedCount: number | null;
  linesCount: number | null;
  linesImportedCount: number | null;

  currentUIStep: number;
  config: any;
  contextName: string;
}
export interface ImportColumnDefinition {
  id: number;
  propertyName: string;
  columnNames: string[];
  allowRange: boolean;
  isMandatory: boolean;
}

export interface ImportColumnMapping {

  id: number;

  columnDefinition: ImportColumnDefinition;
  columnStartIndex: number | null;
  columnEndIndex: number | null | string;
  columnStartHeader: string;
  columnEndHeader: string;
  importSessionId: number;
  importSession: ImportSession;
  defaultValue: string;
}

export interface SheetDTO {
  index: number;
  name: string;
}
export interface HeaderLabel {
  index: number;
  columnName: string;
  fullName: string;
}
export interface ImportConfig {
  id: number;

  importSessionId: number;
  importSession: ImportSession;
}

export interface ImportConfigMetering extends ImportConfig {
  separatorToInsert: string | null;
  separator: string | null;
}

export interface ImportConfigThirdParty extends ImportConfig {
  thirdPartyTypeId: number | null;
}
