/**
 * ParkSmarter API data models.
 *
 * Two casing worlds exist:
 *   - This client's *inputs* use friendly camelCase (see the `*Params` types).
 *   - The server speaks PascalCase ("PSJSON"). Response models below therefore use
 *     the exact server field spellings recovered from the app. Response interfaces
 *     carry an index signature because not every field is guaranteed on every call;
 *     the well-known fields are typed explicitly. Run a live capture to lock down
 *     the optional tail for a given endpoint if you need exhaustiveness.
 */

/**
 * The common status/token-refresh envelope embedded in most authenticated
 * responses as `Response`. `Auth_Token` here is usually null but, when present,
 * is a rolling refresh of the user token (the client stores it automatically).
 * CONFIRMED via live capture.
 */
export interface ResponseEnvelope {
  Auth_Token: string | null;
  Message: string | null;
  Status: string | null;
}

/**
 * Casing note (CONFIRMED via live capture): the meter/zone *response* uses
 * `ZoneId` / `SpaceId` / `CustomerId` (lowercase "d"), while estimate & session
 * *requests* expect `ZoneID` / `SpaceID` / `CustomerID` (capital "ID"). When you
 * feed a captured Zone into an estimate/session, read `zone.CustomerId` /
 * `space.SpaceId` and pass them as the client's camelCase params — the client
 * emits the capital-ID request spelling for you.
 */

/* ------------------------------------------------------------------ */
/* Auth & account                                                      */
/* ------------------------------------------------------------------ */

export interface LoginWithPhoneParams {
  /** Phone number, digits only (no country code prefix). */
  phoneNumber: string;
  password: string;
}

export interface LoginWithAppleParams {
  emailAddress: string;
  appleId: string;
  providerAuth: string;
  providerIdentity: string;
}

/**
 * POST /api/Auth response (login). CONFIRMED: `{ Status, Message, Auth_Token }`.
 * Auth_Token is persisted automatically; SessionId is delivered separately (by
 * bootstrap / headers) and also persisted.
 */
export interface AuthResponse {
  Status?: string;
  Message?: string;
  Auth_Token?: string;
  [key: string]: unknown;
}

export interface SignUpParams {
  emailAddress: string;
  /** Phone number, digits only. */
  mobilePhone: string;
  password: string;
}

export interface RequestResetPasswordParams {
  /** Server `ResetPasswordType`; the app passes a numeric/string reason code. */
  reqType: string | number;
  /** Phone number, digits only. */
  phoneNumber: string;
}

export interface UpdatePasswordParams {
  oldPassword: string;
  newPassword: string;
}

export interface UpdateProfileParams {
  emailAddress: string;
  /** Phone number, digits only. */
  phoneNumber: string;
}

export interface RequestVerifyUserParams {
  /** Phone number, digits only. The client prefixes country code "1". */
  phoneNumber: string;
}

export interface VerifyUserParams {
  /** Phone number, digits only. The client prefixes country code "1". */
  phoneNumber: string;
  /** SMS confirmation code. */
  code: string;
}

export interface UpdateDeviceTokenParams {
  /** Push token (server field `DeviceID`). */
  pushNotificationsToken: string;
  imeiNumber?: string;
  /** Defaults to '1' (Android) as the app hardcodes. */
  deviceType?: string;
  /** BCP-47 language, defaults to the client locale. */
  language?: string;
}

export interface UpdateDeviceTokenResponse {
  Status?: string;
  Message?: string;
  [key: string]: unknown;
}

/** GET /api/User response. CONFIRMED via live capture. */
export interface UserDetail {
  PersonalEmailAddress?: string;
  /** Digits-only phone as a string. */
  PersonalPhone?: string;
  VehicleDetails?: VehicleDetail[];
  CreditCardDetails?: CreditCardDetail[];
  /** Numeric flag (0/1), not a boolean. */
  OffersOptIn?: number;
  [key: string]: unknown;
}

/* ------------------------------------------------------------------ */
/* Vehicles                                                            */
/* ------------------------------------------------------------------ */

/** CONFIRMED via live capture. Note `IsDefault` is a string ("true"/"false"), not a boolean. */
export interface VehicleDetail {
  VehicleID?: number;
  VehiclePlate?: string;
  VehicleState?: string;
  VehicleAlias?: string;
  /** Server returns this as a string, e.g. "true" / "false". */
  IsDefault?: string;
  /** Per-item status fields, usually null on reads. */
  Status?: string | null;
  Message?: string | null;
  [key: string]: unknown;
}

export interface AddVehicleParams {
  plate: string;
  state: string;
  vehicleAlias?: string;
  isDefaultVehicle?: boolean;
}

export interface UpdateVehicleParams extends AddVehicleParams {
  id: number | string;
}

export interface VehicleMutationResponse {
  Status?: string;
  [key: string]: unknown;
}

/* ------------------------------------------------------------------ */
/* Credit cards                                                        */
/* ------------------------------------------------------------------ */

/**
 * CONFIRMED via live capture. The PAN is never returned — only `CCFirstSix` +
 * `CCLastFour`. `CCDefault` comes back as a string ("true"/"false"). Note the
 * response uses `ParentPBPCardId`, whereas the add/update *request* uses `ParentCCID`.
 */
export interface CreditCardDetail {
  CCID?: number;
  CCAlias?: string;
  /** First 6 digits (BIN), numeric string. */
  CCFirstSix?: string;
  /** Last 4 digits, numeric string. */
  CCLastFour?: string;
  CCExpDate?: string;
  CCZip?: string;
  /** String "true"/"false", not a boolean. */
  CCDefault?: string;
  ParentPBPCardId?: number | null;
  /** Per-item status fields, usually null on reads. */
  Status?: string | null;
  Message?: string | null;
  [key: string]: unknown;
}

export interface AddCardParams {
  cardNumber: string;
  alias?: string;
  /** Expiry, format as the app sends it (e.g. "MM/YY"). */
  expDate: string;
  zipCode: string;
  isDefaultCard?: boolean;
  /** Present when editing an existing card (server `ParentCCID`). */
  id?: number | string;
}

export interface SetDefaultCardParams {
  id: number | string;
  isDefaultCard: boolean;
}

/* ------------------------------------------------------------------ */
/* Meters / zones                                                      */
/* ------------------------------------------------------------------ */

export interface LatLng {
  latitude: number;
  longitude: number;
}

/** A rate/time policy slot within a space. CONFIRMED via live capture. */
export interface SpacePolicy {
  CurrentSlot?: boolean;
  DayNumber?: number;
  DisplayString?: string;
  StartDateTime?: string;
  EndDateTime?: string;
  StartTimeDisplay?: string;
  EndTimeDisplay?: string;
  EventRateFlag?: boolean;
  MaxTime?: number;
  MessageHeader?: string;
  MessageText?: string;
  Rate?: number;
  RateType?: string;
  [key: string]: unknown;
}

/**
 * A single space within a zone. CONFIRMED via live capture.
 * Note the id is `SpaceId` (lowercase "d") here; estimate/session requests want
 * the capital-ID `SpaceID` (the client maps camelCase params to that spelling).
 */
export interface Space {
  SpaceId?: number;
  SpaceName?: string;
  SSPMSpaceId?: number;
  MeterPurchaseType?: number;
  OccupancyStatus?: number;
  Policies?: SpacePolicy[];
  [key: string]: unknown;
}

/**
 * A parking zone/meter as returned inside `Zones`. CONFIRMED via live capture.
 * `ScannerCode` is the value encoded in kiosk QR codes; `TerminalSerNo` is the
 * printed serial. Both drive the scan / lookup features.
 */
export interface Zone {
  ZoneId?: number;
  ZoneGuid?: string;
  ZoneName?: string;
  ZoneLocation?: string;
  ZonePlates?: unknown;
  /** Printed serial number (numeric string). */
  TerminalSerNo?: string;
  /** QR-encoded scanner code. */
  ScannerCode?: string;
  Lat?: number;
  Long?: number;
  CustomerId?: number;
  CustomerName?: string;
  /** Minutes offset / IANA-less numeric zone id as returned. */
  TimeZone?: number;
  DSTAdjust?: number;
  CityLogo?: string;
  DepartmentLogo?: string;
  BackgroundColor?: string;
  /** Returned as a numeric string. */
  ForegroundColor?: string;
  MinimumAmount?: number;
  MaxTime?: number;
  MeterType?: string;
  MeterTypeId?: number;
  /** Base rate, returned as a string. */
  Rate?: string;
  ProgressiveRate?: number;
  PercentageFull?: number;
  IsAllowOverAir?: boolean;
  IsAllowBLE?: boolean;
  IsExtension?: boolean;
  IsPaid?: boolean;
  Spaces?: Space[];
  [key: string]: unknown;
}

/** GET /api/Meter and /api/MeterList. CONFIRMED via live capture. */
export interface MetersResponse {
  Zones?: Zone[] | null;
  Response?: ResponseEnvelope;
  [key: string]: unknown;
}

/* ------------------------------------------------------------------ */
/* Parking lots (ParkingLogix)                                         */
/* ------------------------------------------------------------------ */

/** One level/section within a ParkingLogix lot. CONFIRMED via live capture. */
export interface ParkingLotDetail {
  ParkingLogixLotDetailId?: number;
  ParkingLogixLotId?: number;
  Level?: number;
  TotalSpaces?: number;
  FreeSpaces?: number;
  [key: string]: unknown;
}

/** CONFIRMED via live capture. Per-level occupancy lives in ParkingLogixLotDetails. */
export interface ParkingLot {
  ParkingLogixLotId?: number;
  LotName?: string;
  LocationAddress?: string;
  Lat?: number;
  Long?: number;
  TotalSpaces?: number;
  DefaultFree?: boolean;
  ParkingLogixLotDetails?: ParkingLotDetail[];
  [key: string]: unknown;
}

export interface ParkingLotsResponse {
  ParkingLogixLots?: ParkingLot[] | null;
  Response?: ResponseEnvelope;
  [key: string]: unknown;
}

/* ------------------------------------------------------------------ */
/* Estimates                                                           */
/* ------------------------------------------------------------------ */

export interface MultiEstimateParams {
  zoneId: number | string;
  spaceId: number | string;
  customerId: number | string;
  /** Zone minimum credit (server `MinCreditAmount`). */
  minCreditAmount?: number | string;
  vehicleId: number | string;
  /** Optional BLE encrypted bytes string. */
  bleEncBytes?: string;
}

export interface SingleEstimateParams {
  zoneId: number | string;
  spaceId: number | string;
  customerId: number | string;
  /** Server `ParkingDuration`, in minutes. */
  durationInMinutes: number;
  vehicleId: number | string;
  /** Server `CCID` — credit card id. */
  creditCardId: number | string;
}

export interface ItemsEstimateParams {
  zoneId: number | string;
  spaceId: number | string;
  customerId: number | string;
  vehicleId: number | string;
}

/**
 * One priced duration option. CONFIRMED via live capture.
 * Money/id fields come back as numeric *strings* here.
 */
export interface ParkingDetail {
  Minutes?: number;
  StartTime?: string;
  EndTime?: string;
  ParkingCost?: string;
  TransactionFee?: string;
  CurrentAmountPaid?: number;
  CustomerID?: string;
  CustomerName?: string;
  Zone?: string;
  ZoneID?: string;
  Space?: string;
  SpaceID?: string;
  VehicleID?: string;
  VehicleNumber?: string | null;
  CCNumber?: string | null;
  PricingToken?: string | null;
  TimeZone?: number;
  DSTAdjust?: number;
  [key: string]: unknown;
}

/** GET /api/ParkingEstimateMulti. CONFIRMED via live capture (a full price ladder). */
export interface MultiEstimateResponse {
  ParkingDetail?: ParkingDetail[];
  MinTime?: number;
  MaxTime?: number;
  TimeRemaining?: number;
  JumpRateEnabled?: boolean;
  JumpRateThreshold?: number;
  JumpRateSetValue?: number;
  Response?: ResponseEnvelope;
  [key: string]: unknown;
}

/** GET /api/ParkingEstimate. CONFIRMED via live capture (a single priced option). */
export interface SingleEstimateResponse {
  ParkingDetail?: ParkingDetail;
  MinTime?: number;
  MaxTime?: number;
  CurrentCustomerDateTime?: string;
  Response?: ResponseEnvelope;
  [key: string]: unknown;
}

/** GET /api/ParkingEstimateItems. CONFIRMED via live capture. */
export interface ItemsEstimateResponse {
  ZoneID?: number;
  ZoneName?: string;
  SpaceID?: number;
  SpaceName?: string;
  CustomerID?: number;
  CustomerName?: string;
  PurchaseMode?: string;
  Items?: unknown[] | null;
  TimeStampUTC?: number;
  TimeZone?: number;
  DSTAdjust?: number;
  Response?: ResponseEnvelope;
  [key: string]: unknown;
}

/* ------------------------------------------------------------------ */
/* Parking sessions                                                    */
/* ------------------------------------------------------------------ */

export interface StartParkingSessionParams {
  creditCardId: number | string;
  spaceId: number | string;
  customerId: number | string;
  zoneId: number | string;
  vehicleId: number | string;
  /** ISO/formatted start time as the server expects. */
  startTime: string;
  endTime: string;
  /** Minutes purchased (server `TimePurchased`). */
  minutesToPurchase: number;
  /** Base cost, dollars (server `ParkingCost`). */
  parkingCost: number;
  /** Fee, dollars (server `TransactionFee`). Defaults to 0. */
  transactionFee?: number;
  /** Zone minimum credit (server `MinCreditAmount`). */
  minCreditAmount?: number;
  meterTypeId: number | string;
  /** Optional BLE encrypted bytes string. */
  bleEncBytes?: string;
}

/**
 * POST /api/Session. CONFIRMED via live capture. Returns HTTP 200 even on a
 * declined charge — check `Response.Status === 'Error'` (the client does this and
 * throws). `OriginalErrorMessage` carries the gateway reason (e.g. "DECLINED").
 */
export interface StartParkingSessionResponse {
  Response?: ResponseEnvelope;
  BleEncBytes?: string | null;
  PBPParkingSessionId?: number;
  OriginalErrorMessage?: string;
  StartTime?: string | null;
  EndTime?: string | null;
  TimePurchased?: string | null;
  ZoneID?: number | string | null;
  Zone?: string | null;
  SpaceID?: number | string | null;
  Space?: string | null;
  VehicleNumber?: string | null;
  Lat?: number | null;
  Long?: number | null;
  TransactionFee?: string | number | null;
  Amount?: string | number | null;
  AmountCharged?: string | number | null;
  [key: string]: unknown;
}

/** UNCONFIRMED element shape (no active sessions on the test account). */
export interface ActiveSession {
  TransactionID?: number | string;
  ZoneName?: string;
  SpaceName?: string;
  Space?: string;
  StartTime?: string;
  EndTime?: string;
  StartTimeDisplay?: string;
  EndTimeDisplay?: string;
  TimeRemaining?: number | string;
  VehiclePlate?: string;
  VehicleNumber?: string;
  Amount?: number | string;
  IsExtension?: boolean;
  [key: string]: unknown;
}

/** GET /api/ParkingSession. Envelope CONFIRMED; element shape UNCONFIRMED (no active sessions in test account). */
export interface ActiveSessionsResponse {
  ParkingSession?: ActiveSession[] | null;
  CurrentCustomerTime?: string | null;
  Response?: ResponseEnvelope;
  [key: string]: unknown;
}

/** UNCONFIRMED element shape (no past sessions on the test account). */
export interface PastSession {
  TransactionID?: number | string;
  ZoneName?: string;
  StartTime?: string;
  EndTime?: string;
  Amount?: number | string;
  PaymentType?: string;
  PaymentDisplay?: string;
  VehiclePlate?: string;
  IsPaid?: boolean;
  [key: string]: unknown;
}

/** GET /api/Session. Envelope CONFIRMED; element shape UNCONFIRMED (no past sessions in test account). */
export interface PastSessionsResponse {
  Session?: PastSession[] | null;
  Response?: ResponseEnvelope;
  [key: string]: unknown;
}

export interface PastSessionsParams {
  currentPage?: number | string;
  pageSize?: number | string;
}

/* ------------------------------------------------------------------ */
/* Receipts                                                            */
/* ------------------------------------------------------------------ */

export interface ParkingReceipt {
  TransactionID?: number | string;
  ZoneName?: string;
  StartTime?: string;
  EndTime?: string;
  Amount?: number | string;
  Total?: number | string;
  TotalCost?: number | string;
  TransactionFee?: number | string;
  PaymentType?: string;
  VehiclePlate?: string;
  [key: string]: unknown;
}

/** UNCONFIRMED (no receipts on the test account) — field names from static analysis. */
export interface ReceiptResponse {
  ParkingReceipt?: ParkingReceipt;
  Response?: ResponseEnvelope;
  [key: string]: unknown;
}

/* ------------------------------------------------------------------ */
/* Notification settings                                               */
/* ------------------------------------------------------------------ */

/** One toggle group within notification settings. */
export interface NotificationSetting {
  messagesEnabled?: boolean;
  emailsEnabled?: boolean;
  messages?: boolean;
  emails?: boolean;
}

/** Client-side view of the settings (server sends a numeric bitmask in `Settings`). */
export interface NotificationSettings {
  parkingReceipt?: NotificationSetting;
  overnight?: NotificationSetting;
  tenMin?: NotificationSetting;
  fifteenMin?: NotificationSetting;
  sessionEnded?: NotificationSetting;
  sessionStart?: NotificationSetting;
}

/** GET /api/Setting. CONFIRMED: `{ Response, Settings }`. */
export interface RawSettingsResponse {
  /** Server bitmask as a numeric string. Decode per the app's expandSettings logic. */
  Settings?: string;
  Response?: ResponseEnvelope;
  [key: string]: unknown;
}

/** GET /api/State?ID=…. CONFIRMED wrapper `{ StatesResult }` (requires an ID; 404s without). */
export interface StatesResponse {
  StatesResult?: StateItem[];
  [key: string]: unknown;
}

/* ------------------------------------------------------------------ */
/* Content / misc                                                      */
/* ------------------------------------------------------------------ */

/** Terms/Privacy/About all return `{ Value: string }`. */
export interface ValueResponse {
  Value?: string;
  [key: string]: unknown;
}

export interface FAQItem {
  Question?: string;
  Answer?: string;
  [key: string]: unknown;
}

export interface FAQResponse {
  FAQs?: FAQItem[];
  [key: string]: unknown;
}

/** GET /api/ApplicationValidity — feature flags + maintenance + session bootstrap. */
export interface ApplicationValidityResponse {
  SessionId?: string;
  RecommendUpgrade?: boolean;
  ForceUpgrade?: boolean;
  IsParkingEstimateMultiEnabled?: boolean;
  Config?: {
    IsInMaintenanceMode?: boolean;
    ExtendedVariablePBPZoneIds?: unknown;
    ExtendedVariableRateMaxDayMinutes?: number;
    ExtendedVariableRateMaxDay?: number;
    ExtendedVariableMultiDayValueThreshold?: number;
    ExtendedVariableRateSingleHourRate?: number;
    ExtendedVariableRateMaxDayJump?: number;
    ExtendedVariableRateMaxDayValueDollar?: number;
    ExtendedVariableRateMaxMode?: unknown;
    UseLimitedMetersFetch?: boolean;
    UseLoadMetersButton?: boolean;
    UseReloadMetersOnResume?: boolean;
    UseApplePay?: boolean;
    UseGooglePay?: boolean;
    ApplePayHostAddress?: string;
    UseSearchBySpace?: boolean;
    [key: string]: unknown;
  };
  [key: string]: unknown;
}

export interface StateItem {
  [key: string]: unknown;
}
