import type { PropertyValues } from "lit";
import type { GenericController, T9nMeta } from "@arcgis/lumina/controllers";
import type { GenericT9nStrings } from "@arcgis/toolkit/intl";
import type { LitElement, EventEmitter } from "@arcgis/lumina";
import type { EffectiveHourFormat, HourFormat, Meridiem } from "../utils/time.js";
import type { Locale, NumberingSystem } from "../utils/locale.js";

export const useTime: (component: LitElement & TimeComponent) => TimeController;

export interface TimeComponent extends LitElement {
  /**
   * Specifies the component's hour format, where:
   *
   * `"user"` displays the user's locale format,
   * `"12"` displays a 12-hour format, and
   * `"24"` displays a 24-hour format.
   */
  hourFormat: HourFormat;
  /**
   * Translated messages and locale information
   *
   * @internal
   */
  messages: Partial<GenericT9nStrings> | T9nMeta<GenericT9nStrings>;
  /** Specifies the Unicode numeral system used by the component for localization. */
  numberingSystem: NumberingSystem;
  /** Specifies the granularity the component's `value` must adhere to (in seconds). */
  step: number;
  /** The component's time value in ISO (24-hour) format. */
  value: string | null;
}

export class TimeController extends GenericController<TimeProperties, TimeComponent> {
  calciteTimeChange: EventEmitter<string>;
  fractionalSecond?: string | null;
  handleFractionalSecondKeyDownEvent: (event: KeyboardEvent) => void;
  handleHourKeyDownEvent: (event: KeyboardEvent) => void;
  handleMeridiemKeyDownEvent: (event: KeyboardEvent) => void;
  handleMinuteKeyDownEvent: (event: KeyboardEvent) => void;
  handleSecondKeyDownEvent: (event: KeyboardEvent) => void;
  hour?: string | null;
  hourFormat?: EffectiveHourFormat | null;
  locale?: Locale | null;
  /** @default "." */
  localizedDecimalSeparator: string;
  localizedFractionalSecond?: string | null;
  localizedHour?: string | null;
  localizedHourSuffix?: string | null;
  localizedMeridiem?: string | null;
  localizedMinute?: string | null;
  localizedMinuteSuffix?: string | null;
  localizedSecond?: string | null;
  localizedSecondSuffix?: string | null;
  meridiem?: Meridiem | null;
  meridiemOrder?: number | null;
  minute?: string | null;
  second?: string | null;
  /** @default false */
  userChangedValue: boolean;
  decrementHour(): void;
  decrementMinute(): void;
  decrementSecond(): void;
  hostConnected(): void;
  /** @param changes */
  hostUpdate(changes: PropertyValues): void;
  incrementHour(): void;
  incrementMinute(): void;
  incrementSecond(): void;
  /** @param direction */
  nudgeFractionalSecond(direction: "up" | "down"): void;
  /**
   * @param value
   * @param userChangedValue
   */
  setValue(value: string | null, userChangedValue?: boolean): void;
  /**
   * @param key
   * @param value
   */
  setValuePart(key: "hour" | "minute" | "second" | "fractionalSecond" | "meridiem", value?: number | string | Meridiem): void;
  /** @param direction */
  toggleMeridiem(direction: "down" | "up"): void;
}

export type TimeProperties = {
  /** Change event that fires when the value is committed on Enter keypress or blur */
  calciteTimeChange: CustomEvent<string>;
  /** The fractional second portion of the time value. */
  fractionalSecond: string;
  /** The hour portion of the time value (in ISO 24-hour format). */
  hour?: string;
  /**
   * The effective hour format, calculated based on the component's hour-format property.
   * The component's hour-format of "user" will resolve to the locale's default hour format.
   *
   * `"12"` displays a 12-hour format, and
   * `"24"` displays a 24-hour format.
   */
  hourFormat: EffectiveHourFormat;
  /** The language and region code to localize the time value. */
  locale: Locale;
  /** The decimal separator used by the locale. */
  localizedDecimalSeparator: string;
  /** The decimal separator used by the locale. */
  localizedFractionalSecond: string;
  /** The localized fractional second portion of the time value. */
  localizedHour: string;
  /** The hour suffix used by the locale. */
  localizedHourSuffix: string;
  /** The localized meridiem portion of the time value, when hourFormat resolves to 12. */
  localizedMeridiem: string;
  /** The localized minute portion of the time value. */
  localizedMinute: string;
  /** The localized minute suffix used by the locale. */
  localizedMinuteSuffix: string;
  /** The localized second portion of the time value. */
  localizedSecond: string;
  /** The localized second suffix used by the locale. */
  localizedSecondSuffix: string;
  /**
   * The effective meridiem of the time value, when hourFormat resolves to 12.
   *
   * `"AM"` for hours between 0 and 12
   * `"PM"` for hours between 12 and 23
   */
  meridiem: Meridiem;
  /** An integer representing the order in which the meridiem appears for the locale within an array of values returned by Intl.DateTimeFormat. */
  meridiemOrder: number;
  /** The minute portion of the time value. */
  minute?: string;
  /** The second portion of the time value. */
  second: string;
};