import { getTimezoneOffset } from "date-fns-tz";

type PlainPartsAndTimezone = {
  plaindate: number;
  plaintime: number;
  timezoneName: string;
};
type TimestampAndTimezone = {
  timestamp: number;
  timezoneName: string;
};
export class Timestamp {
  /** Generates a copy of the timestamp with the same UTC date but a UTC time of midnight */
  static toPlainDate(timestamp: number) {
    // 1688268612123
    const date = new Date(timestamp); // 2023-07-02T03:30:12.123Z
    date.setUTCHours(0, 0, 0, 0); // 2023-07-02T00:00:00.000Z
    return date.valueOf(); // 1688256000000
  }

  /** Generates a copy of the timestamp with a UTC date of Jan 1 1970 but the same UTC time */
  static toPlainTime(timestamp: number) {
    // 1688268612123
    const date = new Date(timestamp); // 2023-07-02T03:30:12.123Z
    date.setUTCFullYear(1970, 0, 1); // 1970-01-01T03:30:12.123Z
    return date.valueOf(); // 12612123
  }

  static plainPartsToTimestamp({
    plaindate, // 1696118400000 (2023-10-01T00:00:00.000Z)
    plaintime, // 10800000 (1970-01-01T03:00:00.000Z)
    timezoneName, // Australia/Adelaide
  }: PlainPartsAndTimezone): TimestampAndTimezone {
    const utc = this.toPlainDate(plaindate) + this.toPlainTime(plaintime); // 1696129200000 (2023-10-01T03:00:00.000Z)
    const offset = getTimezoneOffset(timezoneName, utc); // 37800000 (+10:30)
    return {
      timestamp: utc - offset, // 1696091400000 (2023-09-30T16:30:00.000Z) (Sun Oct 01 2023 03:00:00 GMT+1030 (Australian Central Daylight Time))
      timezoneName: timezoneName,
    };
  }

  static timestampToPlainParts({
    timestamp, // 1688268612123 (2023-07-02T03:30:12.123Z) (Sat Jul 01 2023 20:30:12 GMT-0700 (Pacific Daylight Time))
    timezoneName, // "America/Los_Angeles"
  }: TimestampAndTimezone): PlainPartsAndTimezone {
    const offset = getTimezoneOffset(timezoneName, timestamp); // -25200000
    const zoned = timestamp + offset; // 1688243412123 (2023-07-01T20:30:12.123Z)
    const plaindate = Timestamp.toPlainDate(zoned); // 1688169600000 (2023-07-01T00:00:00.000Z)
    const plaintime = Timestamp.toPlainTime(zoned); // 73812123 (1970-01-01T20:30:12.123Z)
    return {
      plaindate: plaindate,
      plaintime: plaintime,
      timezoneName: timezoneName,
    };
  }
}
