import { IFleetApi } from "./interfaces/i-fleet-api";
import { DriversListRequest, DriversListRequestFields } from "./models/driver/drivers-list-request";
import { DriversListResponse } from "./models/driver/drivers-list-response";
import { AddTransactionQueryRequest } from "./models/transaction/add-transaction-query-request";
import { AddTransactionResponse } from "./models/transaction/add-transaction-query-response";
import { HttpClientFactory } from "./interfaces/http-client-factory";
import { AxiosInstance } from "axios";
import { Configuration } from "./models/configuration";
import { DriverProfile } from "./models/driver/driver-profile";
import { OrderRequestOptionsSchema, OrdersListRequestOptions } from "./models/orders/orders-list.request";
import { OrdersListResponse } from "./models/orders/orders-list.response";
import { exponentialDelay } from "axios-retry";

export class FleetTaxiYandexRepository implements IFleetApi {
  private readonly chunkSize = 1000;
  private http: AxiosInstance;
  constructor(
    private config: Configuration,
    private httpClientFactory: HttpClientFactory,
  ){
    this.http = httpClientFactory({ 
      defaults: {
        headers: {
          "X-API-Key": config.fleetApiKey,
          "X-Client-ID": config.fleetClientId
        }
      }, 
      rateLimitOptions: { 
        maxRPS: 2,
      }, 
      retryConfig: {
        retries: 15,
        retryDelay: exponentialDelay,
        retryCondition: (err) => err?.response?.status === 429,
        onRetry: (retryCount, error, requestConfig) => {
          console.debug('axios retry', retryCount, error, requestConfig);
        },
      } 
    });
  }

  async postGetDriverProfilesList(requestBodyParams: DriversListRequest): Promise<DriversListResponse> {
    const res = await this.http.post<DriversListResponse>(`${this.config.fleetApiEndpoint}/v1/parks/driver-profiles/list`, requestBodyParams);
    return res.data;
  }
  
  async getOrders(options: OrdersListRequestOptions): Promise<OrdersListResponse> {
    OrderRequestOptionsSchema.parse(options);
   
    const res = await this.http.post<OrdersListResponse>(`${this.config.fleetApiEndpoint}/v1/parks/orders/list`, {
      limit: options.limit,
      cursor: options.cursor,
      query: {
        park: {
          id: this.config.fleetParkId,
          order: {
            "booked_at": {
              "from": options.date?.start_time,
              "to": options.date?.end_time
            },
            statuses: ["complete"],
            categories: [
              "econom",
              "comfort",
              "comfort_plus",
              "business",
              "cargo",
              "minivan",
            ]
          }
        }
      }
    });
    
    return res.data;
  }
  
  async getAllDrivers(requestFields: DriversListRequestFields): Promise<Partial<DriverProfile>[]> {
    let index = 0;
    let driversProfile : Partial<DriverProfile>[] = [];
    let lastResultCount = 0;

    do{
      const req: DriversListRequest = {
        fields: requestFields,
        limit: this.chunkSize,
        offset: index,
        query: {
          park: { 
            id: this.config.fleetParkId
          },
          text: ""
        }
      }
      const res = await this.postGetDriverProfilesList(req);
      driversProfile = driversProfile.concat(res?.driver_profiles);
      lastResultCount = res?.driver_profiles?.length ?? 0;
      index += lastResultCount;
    }
    while(lastResultCount >= this.chunkSize)
    return driversProfile;
  }

  async postAddDriverProfilesTransactions(idempotencyToken: string, requestBodyParams: AddTransactionQueryRequest): Promise<AddTransactionResponse> {
    const res = await this.http.post<AddTransactionResponse>(`${this.config.fleetApiEndpoint}/v2/parks/driver-profiles/transactions`, requestBodyParams, {
      headers: {
        "X-Idempotency-Token": idempotencyToken
      }
    });
    return res.data;
  }
}