import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { OdataGridHelper } from '../_shared/utils/odata-grid-helper';
import { map, Observable } from 'rxjs';
import { State } from '@progress/kendo-data-query';
import { GridDataResult } from '@progress/kendo-angular-grid';
import * as util from '../_shared/utils/util';

export interface Item {
  Id: number;
  ScheduleName: string;
  Pipeline: string;
  ContractType: string;
  Product: string;
}

export class Detail {
  id: number = null;
  scheduleName: string = null;
  pipelineId: number = null;
  contractTypeId: number = null;
  rates: DetailRate[] = null;
  discounts: DetailDiscount[] = null;
  productId: number[] = null;

  constructor(partialDetail: Partial<Detail>, requiredData?: RequiredData) {
    Object.assign(this, partialDetail);
    this.updateStrings(requiredData);
  }

  public updateStrings(requiredData: RequiredData): void {
    if (requiredData) {
      this.rates.forEach(rate => {
        rate.rateType = rate.rateTypeId !== null ? requiredData.rateTypes.find(x => x.id === rate.rateTypeId).name : null;
        rate.applicationRule = rate.applicationRuleId !== null ? requiredData.applicationRules.find(x => x.id === rate.applicationRuleId).name : null;
      });

      const metersModified = requiredData.meters.map(x => { return { id: x.meterId, name: x.meterName } });

      this.discounts.forEach(disc => {
        disc.rateType = disc.rateTypeId !== null ? requiredData.rateTypes.find(x => x.id === disc.rateTypeId).name : null;
        disc.fromZones = util.idsToNamesJoin(disc.fromZoneIds, requiredData.zones);
        disc.fromMeters = util.idsToNamesJoin(disc.fromMeterIds, metersModified);
        disc.toZones = util.idsToNamesJoin(disc.toZoneIds, requiredData.zones);
        disc.toMeters = util.idsToNamesJoin(disc.toMeterIds, metersModified);
        disc.counterparties = util.idsToNamesJoin(disc.counterpartyIds, requiredData.counterparties);
      });
    }
  }
}

export interface DetailRate {
  id: number;
  rateTypeId: number;
  effectiveDate: Date;
  applicationRuleId: number;
  singleRate: number;
  documents: util.DocItem[];
  notes: string;
  multiRateData: DetailRateData[];

  rateType: string;
  applicationRule: string;
}

export interface DetailRateData {
  orderId: number;
  startMonth: number;
  endMonth: number;
  fromZoneId: number;
  toZoneId: number;
  rate: number;
}

export interface DetailDiscount {
  id: number;
  rateTypeId: number;
  effectiveDate: Date;
  expirationDate: Date;
  rate: number;
  fromZoneIds: number[];
  fromMeterIds: number[];
  toZoneIds: number[];
  toMeterIds: number[];
  counterpartyIds: number[];
  documents: util.DocItem[];
  notes: string;

  rateType: string;
  fromZones: string;
  fromMeters: string;
  toZones: string;
  toMeters: string;
  counterparties: string;
}

export interface RequiredData {
  hasModifyPermission: boolean;
  counterparties: util.IdName[];
  pipelines: Pipeline[];
  zones: Zone[];
  meters: Meter[];
  contractTypes: util.IdName[];
  rateTypes: util.IdName[];
  applicationRules: util.IdName[];
  months: util.IdName[];
  products: util.IdName[];
}

export interface Pipeline {
  pipeId: number;
  pipeName: string;
  isGasPipe: boolean;
  isCrudePipe: boolean;
  productIds: number[];
}

export interface Zone {
  id: number;
  name: string;
  pipelineId: number;
}

export interface Meter {
  meterId: number;
  meterName: string;
  meterNum: number;
  zoneId: number;
  pipeId: number;
  isGasMeter: boolean;
  isCrudeMeter: boolean;
  productId: number;
}

@Injectable({
  providedIn: 'root'
})
export class PipeRateScheduleService extends OdataGridHelper {
  private baseUrl = `${window.location.origin}/api/PipeRateSchedule`;
  http = inject(HttpClient);

  requiredData$ = this.http.get<RequiredData>(`${this.baseUrl}/getRequiredData`)

  getItems(state: State): Observable<GridDataResult> {
    return this.fetch(`GetPipeRateScheduleItems`, state, null, false)
  }

  getDetail(id: number): Observable<Detail> {
    const url = `${this.baseUrl}/GetDetail?id=${id}`;
    return this.http.get<Detail>(url);
  }

  saveDetail(detail: Detail, saveType: util.SaveType): Observable<number> {
    detail.rates = util.convertDatesToDateOnlyStrings(detail.rates, ["effectiveDate"]);
    detail.discounts = util.convertDatesToDateOnlyStrings(detail.discounts, ["effectiveDate", "expirationDate"]);
    const url = `${this.baseUrl}/SaveDetail?saveType=${saveType}`;
    return this.http.put<number>(url, detail);
  }

  deleteDetail(id: number) {
    const url = `${this.baseUrl}/DeleteDetail/${id}`;
    return this.http.delete(url);
  }

  exportItems(state: State, fileNameOriginal: string) {
    return this.fetchExport(`GetPipeRateScheduleItems`, state, null, fileNameOriginal);
  }

  downloadDoc(fileNameOriginal: string, fileNameOnDisk: string, rateDocType: number): Observable<{ fileBlob: Blob, fileName: string }> {
    const url = `${this.baseUrl}/DownloadDoc?fileNameOnDisk=${fileNameOnDisk}&rateDocType=${rateDocType}`;
    return this.http.get(url, { observe: 'response', responseType: 'blob' }).pipe(
      map(result => {
        const fileBlob = result.body;
        const fileName: string = result.body.type === "text/plain" ? "Error.txt" : fileNameOriginal;
        return { fileBlob, fileName };
      })
    );
  }
}
