import { DefaultPlucky, Plucky } from "plucky_client/plucky";
import { DateTime, Duration, Interval } from "luxon";

export function getPluckyClient(): Plucky {
  // In Production, the Twirp server is expected to be on the same origin as
  // the web server. In Development, it is hosted on a different port.
  const baseAddress =
    process.env.NODE_ENV === "production"
      ? window.location.origin
      : "http://127.0.0.1:8080";

  // Use the global fetch function as our fetcher.
  //
  // Work around a bug that occurs in browser environments that causes errors like
  // Failed to execute 'fetch' on 'Window': Illegal invocation
  // More info: https://github.com/orbitjs/orbit/issues/452
  const fetchFunc = window.fetch.bind(window);

  return new DefaultPlucky(baseAddress, fetchFunc);
}

export interface AppTimeRanges {
  queryRange: Interval;
  timePickerRange: TimePickerRange;
  refreshQueryRange: () => void;
  setTimePickerRange: (timePickerRange: TimePickerRange) => void;
}

export interface QueryRange {
  start: DateTime;
  end: DateTime;
}

export class TimePickerRange {
  static fromAbsolute(interval: Interval): TimePickerRange {
    return new TimePickerRange(interval, undefined);
  }

  static fromRelative(relativeID: string): TimePickerRange {
    return new TimePickerRange(undefined, relativeID);
  }

  readonly absolute?: Interval;
  readonly relativeID?: string;

  constructor(absolute?: Interval, relativeID?: string) {
    this.absolute = absolute;
    this.relativeID = relativeID;
  }

  toString(): string {
    if (this.relativeID) {
      return this.relativeID;
    }
    if (!this.absolute) {
      return "";
    }

    const start = this.absolute.start;
    const end = this.absolute.end;
    const sameDate = start.toISODate() === end.toISODate();
    if (sameDate) {
      return `${start.toLocaleString(
        DateTime.DATETIME_SHORT_WITH_SECONDS
      )} - ${end.toLocaleString(DateTime.TIME_WITH_SECONDS)}`;
    }
    return `${start.toLocaleString(
      DateTime.DATETIME_SHORT_WITH_SECONDS
    )} - ${end.toLocaleString(DateTime.DATETIME_SHORT_WITH_SECONDS)}`;
  }
}

export class RelativeRange {
  static Last5Min = "Last 5 minutes";
  static Last15Min = "Last 15 minutes";
  static Last30Min = "Last 30 minutes";
  static LastHour = "Last hour";
  static Last3Hours = "Last 3 hours";
  static Last6Hours = "Last 6 hours";
  static Last12Hours = "Last 12 hours";
  static LastDay = "Last day";

  static ids = [
    RelativeRange.Last5Min,
    RelativeRange.Last15Min,
    RelativeRange.Last30Min,
    RelativeRange.LastHour,
    RelativeRange.Last3Hours,
    RelativeRange.Last6Hours,
    RelativeRange.Last12Hours,
    RelativeRange.LastDay,
  ];

  private static idToSize = new Map<string, Duration>([
    [RelativeRange.Last5Min, Duration.fromObject({ minutes: 5 })],
    [RelativeRange.Last15Min, Duration.fromObject({ minutes: 15 })],
    [RelativeRange.Last30Min, Duration.fromObject({ minutes: 30 })],
    [RelativeRange.LastHour, Duration.fromObject({ hours: 1 })],
    [RelativeRange.Last3Hours, Duration.fromObject({ hours: 3 })],
    [RelativeRange.Last6Hours, Duration.fromObject({ hours: 6 })],
    [RelativeRange.Last12Hours, Duration.fromObject({ hours: 12 })],
    [RelativeRange.LastDay, Duration.fromObject({ days: 1 })],
  ]);

  static relativeRangeToAbsolute(relativeRangeID: string): Interval {
    const end = DateTime.utc();
    const size =
      RelativeRange.idToSize.get(relativeRangeID) ??
      Duration.fromObject({ hours: 3 });
    return Interval.before(end, size);
  }
}
