// Typdefinitionen für https://sattelpass.com/sdk/sattelpass-api.js

export type SaddleField =
  | "brand"
  | "model"
  | "art"
  | "seat_size"
  | "kammerweite"
  | "seriennummer"
  | "sattel_typ"
  | "sattelbaum"
  | "kopfeisen"
  | "verstellbar"
  | "aktuelle_einstellung"
  | "sattelblatt"
  | "vorschnitt"
  | "pausche"
  | "sitz"
  | "strupfen"
  | "polsterung"
  | "leder"
  | "farbe"
  | "seller_name";

export interface Customer {
  id: string;
  email: string;
  first_name: string;
  last_name: string;
  phone: string;
  notes: string;
  external_id: string | null;
  created_at: string;
  updated_at: string;
}
export interface CustomerInput {
  /** Pflicht – außer bei Angabe von external_id (Kunde nur mit Namen, ohne E-Mail). */
  email?: string;
  first_name?: string;
  last_name?: string;
  phone?: string;
  notes?: string;
  /** Ihre eigene Kunden-ID – Abgleich beim erneuten Senden */
  external_id?: string;
}

export interface SaddleCustomer {
  id: string;
  email: string;
  first_name: string;
  last_name: string;
  phone: string;
}

export interface Saddle extends Record<SaddleField, string | null> {
  id: string;
  short_code: string | null;
  pass_url: string | null;
  external_id: string | null;
  created_via: "app" | "web" | "import" | "api" | "embed" | null;
  is_active: boolean;
  nfc_written_at: string | null;
  last_check_date: string | null;
  stolen_reported_at: string | null;
  customer: SaddleCustomer | null;
  created_at: string;
  updated_at: string;
}

export interface SaddleCreateInput extends Partial<Record<SaddleField, string>> {
  brand: string;
  model: string;
  external_id?: string;
  /** Lagersattel (ohne Kunde): Eingangsdatum fürs Bestandsbuch (ISO 8601), Grundlage von Lager & Umschlag. */
  stock_received_at?: string;
  photo_url?: string;
  /** Adresse auf Ihrem eigenen NFC-Chip (z. B. https://ihr-betrieb.de/o/CODE) – der Sattelpass-Scanner findet den Sattel darüber. */
  chip_url?: string;
  /** Öffentlicher Text des ersten Chronik-Eintrags (z. B. „Ab Werk erfasst“). */
  created_note?: string;
  created_title?: string;
  customer_id?: string;
  customer?: { email: string; first_name?: string; last_name?: string; phone?: string };
}

export type SaddleUpdateInput = Partial<Record<SaddleField, string>> & {
  external_id?: string | null;
  photo_url?: string | null;
  chip_url?: string | null;
  is_active?: boolean;
  last_check_date?: string | null;
};

export interface SaddleListQuery {
  serial?: string;
  external_id?: string;
  short_code?: string;
  q?: string;
  /** Nur seit diesem Zeitpunkt geänderte Sättel (ISO 8601), älteste Änderung zuerst. */
  updated_since?: string;
  limit?: number;
  offset?: number;
}

/** Ergebnis je Sattel einer Sammel-Anlage (POST /saddles/batch). */
export type SaddleBatchResult =
  | { index: number; status: "created"; external_id: string | null; saddle: Saddle }
  | { index: number; status: "exists"; external_id: string | null; saddle_id: string | null }
  | {
      index: number;
      status: "error";
      external_id: string | null;
      error: { code: string; message: string; details?: unknown };
    };

/** Sattel der eigenen Marke, wie ihn der Hersteller sehen darf: ohne Kunde, Händler-ID, Lager- und Verkaufsdaten. */
export interface BrandSaddle extends Record<Exclude<SaddleField, "seller_name">, string> {
  id: string;
  short_code: string | null;
  pass_url: string | null;
  stolen_reported_at: string | null;
  created_at: string;
  /** Liegt der Sattel (noch) im eigenen Konto? */
  in_own_account: boolean;
  /** Ihre Lieferung an den ersten Händler; null, wenn ein anderer Betrieb den Sattel angelegt hat. */
  delivery: { dealer_name: string; delivered_at: string } | null;
  /** Ein Händler hat den Sattel zur Reparatur eingeschickt (volle Chronik lesbar). */
  repair_open: boolean;
}

export interface BrandEvent {
  id: string;
  event_type: string;
  title: string;
  description: string;
  public_note: string;
  event_date: string;
  author_name: string;
  /** Von Ihnen geschrieben */
  own: boolean;
  created_at: string;
}

export interface Repair {
  id: string;
  saddle_id: string;
  note: string;
  dealer_name: string;
  manufacturer_name: string;
  opened_at: string;
  closed_at: string | null;
  closed_by: "manufacturer" | "dealer" | null;
  saddle: Omit<BrandSaddle, "in_own_account" | "delivery" | "repair_open">;
}

/** Ereignisse des Rückkanals (Header X-Sattelpass-Event bzw. WebhookPayload.event). */
export type WebhookEventName =
  | "saddle.created"
  | "saddle.updated"
  | "saddle.owner_changed"
  | "saddle.transferred"
  | "saddle.stolen_reported"
  | "saddle.stolen_cleared"
  | "transfer.accepted"
  | "event.created"
  | "repair.opened"
  | "repair.closed"
  | "brand.event.created"
  | "brand.saddle.stolen_reported"
  | "brand.saddle.stolen_cleared"
  | "test.ping";

export type SaddleEventType = "work_order" | "check" | "fitting" | "repair" | "note" | "sale";

export interface SaddleEvent {
  id: string;
  saddle_id?: string;
  event_type: string;
  title: string;
  description: string;
  public_note: string;
  event_date: string;
  author_user_id?: string;
  created_at: string;
}

export interface SaddleEventCreateInput {
  title: string;
  event_type?: SaddleEventType;
  description?: string;
  /** Sichtbar auf dem öffentlichen Sattelpass. */
  public_note?: string;
  event_date?: string;
}

export interface WebhookEndpoint {
  id: string;
  url: string;
  description: string;
  events: string[];
  active: boolean;
  last_delivery_at: string | null;
  last_status: number | null;
  disabled_reason: string | null;
  created_at: string;
}

export interface WebhookDelivery {
  id: string;
  endpoint_id: string;
  event: string;
  status: "pending" | "sending" | "delivered" | "failed" | "dead";
  attempts: number;
  response_status: number | null;
  last_error: string | null;
  next_attempt_at: string;
  delivered_at: string | null;
  created_at: string;
}

export interface WebhookPayload<T = unknown> {
  id: string;
  event: string;
  created_at: string;
  attempt: number;
  api_version: "v1";
  data: T;
}

export declare class SattelpassApiError extends Error {
  status: number;
  code: string;
  details?: unknown;
  requestId?: string;
}

export interface SattelpassClientOptions {
  apiKey: string;
  /** Standard: https://sattelpass.com/api/v1 */
  baseUrl?: string;
  fetch?: typeof fetch;
}

export declare class SattelpassClient {
  constructor(options: SattelpassClientOptions);
  me(): Promise<{
    api_version: string;
    account: { id: string; display_name: string; roles: string[]; verified: boolean };
    key: {
      id: string;
      kind: "secret" | "embed";
      /** Testschlüssel (sp_test_…): Schreibvorgänge werden nur simuliert. */
      test: boolean;
      scopes: string[];
      rate_limit_per_minute: number;
    };
  }>;
  options(): Promise<{
    brand: string;
    fields: SaddleField[];
    required: string[];
    options: Record<string, { value: string; is_default: boolean }[]>;
  }>;
  saddles: {
    create(
      input: SaddleCreateInput,
      opts?: { idempotencyKey?: string },
    ): Promise<{ saddle: Saddle }>;
    /** Bis zu 100 Sättel in einer Anfrage; Ergebnis je Sattel. Wiederholen ist gefahrlos (external_id). */
    createBatch(saddles: SaddleCreateInput[]): Promise<{
      results: SaddleBatchResult[];
      created: number;
      existing: number;
      failed: number;
      test?: true;
    }>;
    /** Alle seit einem Zeitpunkt geänderten Sättel, älteste Änderung zuerst. */
    listUpdatedSince(
      since: string | Date,
      query?: SaddleListQuery,
    ): Promise<{ saddles: Saddle[]; total: number; limit: number; offset: number }>;
    list(
      query?: SaddleListQuery,
    ): Promise<{ saddles: Saddle[]; total: number; limit: number; offset: number }>;
    get(id: string): Promise<{ saddle: Saddle }>;
    update(id: string, patch: SaddleUpdateInput): Promise<{ saddle: Saddle }>;
    findByExternalId(externalId: string): Promise<Saddle | null>;
    findBySerial(serial: string): Promise<Saddle | null>;
    /** Lager: Eingang („received“), Verkauf an Endkunden („sold“, mit Datum) oder Abgang ohne Verkauf („removed“). */
    stock(
      id: string,
      input: { action: "received" | "sold" | "removed"; at?: string; received_at?: string },
    ): Promise<{ ok: true; action: string; at: string }>;
    /** Sattel eines anderen Kontos (z. B. Hersteller-Chip) in das eigene Konto übernehmen. */
    claim(input: {
      short_code: string;
      customer_id?: string;
      customer?: { email: string; first_name?: string; last_name?: string; phone?: string };
      external_id?: string;
      note?: string;
    }): Promise<{ saddle: Saddle }>;
  };
  events: {
    /** Chronik-Einträge über alle eigenen Sättel; mit since nur neue, älteste zuerst. */
    listAll(query?: { since?: string | Date; limit?: number; offset?: number }): Promise<{
      events: (SaddleEvent & {
        saddle_id: string;
        saddle_short_code: string | null;
        saddle_external_id: string | null;
      })[];
      total: number;
      limit: number;
      offset: number;
    }>;
    list(saddleId: string): Promise<{ events: SaddleEvent[] }>;
    create(saddleId: string, input: SaddleEventCreateInput): Promise<{ event: SaddleEvent }>;
    update(
      saddleId: string,
      eventId: string,
      patch: Partial<SaddleEventCreateInput>,
    ): Promise<{ event: SaddleEvent }>;
    /** Eintrag aus dem Sattelpass entfernen (wird archiviert). */
    remove(saddleId: string, eventId: string): Promise<{ ok: true; id: string }>;
  };
  customers: {
    list(query?: {
      email?: string;
      external_id?: string;
      q?: string;
      /** Nur seit diesem Zeitpunkt geänderte Kunden (ISO 8601). */
      updated_since?: string;
      limit?: number;
      offset?: number;
    }): Promise<{ customers: Customer[]; total: number; limit: number; offset: number }>;
    get(id: string): Promise<{ customer: Customer }>;
    /** Anlegen oder aktualisieren (Abgleich über external_id, sonst E-Mail). */
    upsert(input: CustomerInput): Promise<{ customer: Customer; created: boolean }>;
    update(id: string, patch: Partial<CustomerInput>): Promise<{ customer: Customer }>;
    findByExternalId(externalId: string): Promise<Customer | null>;
    findByEmail(email: string): Promise<Customer | null>;
  };
  public: {
    get(shortCode: string): Promise<{ saddle: Record<string, unknown>; events: SaddleEvent[] }>;
  };
  webhooks: {
    list(): Promise<{ endpoints: WebhookEndpoint[]; deliveries: WebhookDelivery[] }>;
    /** Test-Zustellung (test.ping); mit event liegt in data.sample ein Beispiel dieses Ereignisses. */
    test(
      event?: Exclude<WebhookEventName, "test.ping" | "transfer.accepted">,
    ): Promise<{ ok: true; queued: number; event: "test.ping"; sample_event: string | null }>;
  };
  /** Hersteller-Rückkanal (nur Herstellerkonten). */
  brand: {
    saddles: {
      list(query?: {
        /** Nur Lieferungen seit diesem Zeitpunkt, älteste zuerst. */
        delivered_since?: string | Date;
        /** Genau dieser Sattel der eigenen Marke – auch wenn ihn ein anderer Betrieb angelegt hat. */
        serial?: string;
        short_code?: string;
        limit?: number;
        offset?: number;
      }): Promise<{ saddles: BrandSaddle[]; total: number; limit: number; offset: number }>;
      get(id: string): Promise<{ saddle: BrandSaddle }>;
      findBySerial(serial: string): Promise<BrandSaddle | null>;
    };
    events: {
      /** visibility "own": nur Ihre Einträge; "full": ganze Chronik (eigener Bestand oder offene Reparatur). */
      list(saddleId: string): Promise<{ events: BrandEvent[]; visibility: "own" | "full" }>;
      create(saddleId: string, input: SaddleEventCreateInput): Promise<{ event: SaddleEvent }>;
    };
    repairs: {
      list(query?: {
        status?: "open" | "closed" | "all";
        since?: string | Date;
        limit?: number;
        offset?: number;
      }): Promise<{ repairs: Repair[]; total: number; limit: number; offset: number }>;
      close(id: string): Promise<{ repair: Repair }>;
    };
  };
  request<T = unknown>(
    method: string,
    path: string,
    body?: unknown,
    opts?: { idempotencyKey?: string },
  ): Promise<T>;
}

export declare function verifyWebhookSignature(input: {
  secret: string;
  timestamp: string | number;
  rawBody: string;
  signature: string;
  toleranceSeconds?: number;
}): Promise<boolean>;
