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

export interface Item {
  Id: number;
  ProductionMonth: Date;
  StatementDate: Date;
  Plant: string;
  Producer: string;
  Meter: string;
  StatementDescriptor: string;
  PayoutType: string;
  CombinedMeters: string;
}

export interface CombinedMeter {
  meterName: string;
  meterId: number;
  wellheadVolumeMcf: number;
  wellheadVolumeMmbtu: number;
  pipelineVolume: number;
  wellheadPtrPrice: number;
  liquidsTakePercent: number;
  inKindPvrMcf: number;
  inKindPtrMmbtu: number;
  volumePercent: number;
}

export interface Statement {
  id: number;
  productionMonth: Date;
  statementDate: Date;
  plantId: number;
  statementNotes: string;
  plantNotes: string;
  producerId: number;
  meterId: number;
  statementDescriptorId: number;
  payoutTypeId: number;
  wellheadVolumeMcf: number;
  wellheadVolumeMmbtu: number;
  processedVolumeMcf: number;
  processedVolumeMmbtu: number;
  shrinkMcf: number;
  shrinkMmbtu: number;
  plantFuelMcf: number;
  plantFuelMmbtu: number;
  flareMcf: number;
  flareMmbtu: number;
  bypassMcf: number;
  bypassMmbtu: number;
  plantGainLossMcf: number;
  plantGainLossMmbtu: number;
  inKindPvrMcf: number;
  inKindPtrMmbtu: number;
  recoveredCarbonDioxide: number;
  recoveredEthane: number;
  recoveredPropane: number;
  recoveredIsoButane: number;
  recoveredNormalButane: number;
  recoveredNaturalGasoline: number;
  recoveredScrubber: number;
  theoreticalCarbonDioxide: number;
  theoreticalEthane: number;
  theoreticalPropane: number;
  theoreticalIsoButane: number;
  theoreticalNormalButane: number;
  theoreticalIsoPentane: number;
  theoreticalNormalPentane: number;
  theoreticalNaturalGasoline: number;
  ptrCashoutPrice: number;
  ptrTrans: number;
  ptrFuelPercent: number;
  wellheadPtrPrice: number;
  liquidsTakePercent: number;
  taxes: number | string;
  fractionationFee: number;
  plantProcessingFee: number;
  carbonDioxideFee: number;
  compressionFee: number;
  electricityFee: number;
  stabilizationFee: number;
  miscellaneousFee: number;
  liquidsLiftingFee: number;
  gpmCarbonDioxide: number;
  gpmEthane: number;
  gpmPropane: number;
  gpmIsoButane: number;
  gpmNormalButane: number;
  gpmIsoPentane: number;
  gpmNormalPentane: number;
  gpmHexanePlus: number;
  molePercentNitrogen: number;
  molePercentCarbonDioxide: number;
  molePercentMethane: number;
  molePercentEthane: number;
  molePercentPropane: number;
  molePercentIsoButane: number;
  molePercentNormalButane: number;
  molePercentIsoPentane: number;
  molePercentNormalPentane: number;
  molePercentHexane: number;
  molePercentHeptane: number;
  pipelineGainLossMcf: number;
  pipelineGainLossMmbtu: number;
  allocatedCarbonDioxide: number;
  allocatedEthane: number;
  allocatedPropane: number;
  allocatedIsoButane: number;
  allocatedNormalButane: number;
  allocatedNaturalGasoline: number;
  allocatedScrubber: number;
  pricesId: number;
  chargeProducerFee: boolean;
  electionMcf: number;
  electionMmbtu: number;
  combinedMeters: CombinedMeter[];
}

export interface RequiredData {
  hasModifyPermission: boolean;
  plants: IdName[];
  producers: IdName[];
  payoutTypes: PayoutTypeItem[];
  meters: MeterItem[];
  statementDescriptors: IdName[];
}

export interface MeterItem {
  meterId: number;
  meterName: string;
  plantIds: number[];
  producerIds: number[];
}

export interface Calcs {
  feesTotal: number;
  allocatedTotal: number;
  recoveredTotal: number;
  theoreticalTotal: number;
  gpmTotal: number;
  totalPvrMcf: number;
  totalPtrMmbtu: number;
  processedBtuFactor: number;
  wellheadBtuFactor: number;
}

export interface PriceItem {
  id: number;
  name: string;
  ethanePrice: number;
  propanePrice: number;
  isoButanePrice: number;
  normalButanePrice: number;
  naturalGasolinePrice: number;
  scrubberPrice: number;
  isDefault: boolean;
}

export interface PayoutTypeItem {
  id: number;
  name: string;
  description: string;
}

export interface StatementImportResult {
  changesMessage: string;
  notes: string;
}

export interface PayPtrValues {
  payoutTypeId: number;
  ptrTrans: number;
  ptrFuelPercent: number;
}

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

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

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

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

  saveStatement(statement: Statement, saveType: SaveType): Observable<number> {
    const url = `${this.baseUrl}/SaveStatement?saveType=${saveType}`;
    statement = convertDatesToDateOnlyStrings(statement, ['productionMonth', 'statementDate']);
    return this.http.put<number>(url, statement);
  }

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

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

  getPlantStatementPrices(productionMonth: Date, statementDate: Date, plantId: number, producerId: number): Observable<PriceItem[]> {
    const productionMonthStr = dayjs(productionMonth).format("YYYY-MM-DD");
    const statementDateStr = dayjs(statementDate).format("YYYY-MM-DD");
    const url = `${this.baseUrl}/GetPlantStatementPrices/${productionMonthStr}/${statementDateStr}/${plantId}/${producerId}`;
    return this.http.get<PriceItem[]>(url);
  }

  getRequiredFields(plantId: number, payoutTypeId: number) {
    if (plantId) {
      const payoutTypeIdStr = payoutTypeId ? payoutTypeId : "";
      return this.http.get(this.baseUrl + '/getRequiredFields/' + plantId + '/' + payoutTypeIdStr);
    }
    else {
      return this.http.get(this.baseUrl + '/getRequiredFields');
    }
  };

  getPlantNotes(plantId: number, productionMonth: Date): Observable<string> {
    const productionMonthStr = dayjs(productionMonth).format("YYYY-MM-DD");
    const url = `${this.baseUrl}/GetPlantNotes/${plantId}/${productionMonthStr}`;
    return this.http.get<string>(url);
  };

  getOptionRequiredFields(plantId: number, payoutTypeId: number) {
    const plantIdStr = `/${plantId}`;
    const payoutTypeStr = payoutTypeId ? `/${payoutTypeId}` : '';
    const url = `${this.baseUrl}/getOptionRequiredFields${plantIdStr}${payoutTypeStr}`;
    return this.http.get<string[]>(url);
  };

  getDefaultDescriptorId(productionMonth: Date, plantId: number, producerId: number, meterId: number) {
    const productionMonthStr = dayjs(productionMonth).format("YYYY-MM-DD");
    const meterIdStr = meterId ?? "";
    const url = `${this.baseUrl}/getDefaultDescriptor/${productionMonthStr}/${plantId}/${producerId}/${meterIdStr}`;
    return this.http.get<number>(url);
  };

  getDefaultPayPtrValues(productionMonth: Date, plantId: number, producerId: number, meterId: number, descriptorId: number) {
    const productionMonthStr = dayjs(productionMonth).format("YYYY-MM-DD");
    const descriptorIdStr = descriptorId ?? "";
    //an empty space is needed when meterIdStr is null since it is not the last parameter
    //this avoids a double slash. `//` does not convert to a null on the C# API, but `/ /` works
    const meterIdStr = meterId ?? " ";
    const url = `${this.baseUrl}/getDefaultPayPtrValues/${productionMonthStr}/${plantId}/${producerId}/${meterIdStr}/${descriptorIdStr}`;
    return this.http.get<PayPtrValues>(url);
  };
}
