import { Observable } from 'rxjs';
import { RemissionProcess } from '../models/remission-process';
import { RemissionProduct } from '../models/remission-product';
import { RemissionFilter } from '../models/remission-filter';
import { Printer } from '../models/printer';
import { Product } from '../models/product';
import { RemissionSourceType } from '../types/remission-source.type';
import { Filter } from '../models/filter';
import { RemissionPlacementType } from '../types/remission-placement-types';
import { RemissionSupplier } from '../models/remission-supplier';
import { ShippingDocument } from '../models/shipping-document';
import { ActionResult, CapacityType } from '../models';

export abstract class RemissionService {
  /**
   * Notwendige Informationen für View (Start-Screen) und Starten einer Remission
   * @returns Remission Prozess Default Settings
   */
  abstract createProcess(
    source?: RemissionProcess
  ): Observable<RemissionProcess>;

  /**
   * Wiederaufnahme eines vorhandenen Prozesses
   */
  abstract continueProcess(
    source: RemissionProcess
  ): Observable<RemissionProcess>;

  /**
   * Wiederaufnahme eines vorhandenen Prozesses anhand der PachstückId
   */
  abstract continueProcessFromScan(
    containerId: string
  ): Observable<RemissionProcess>;

  /**
   * Starten einer Remission
   * @param params.remissionProcessId Remissionsnummer
   * @returns Remissionsprozess
   */
  abstract startRemission(params: {
    remissionProcessId: number;
    createShippingDocument?: boolean;
  }): Observable<RemissionProcess>;

  /**
   * Remission abschließen
   * @param params.remissionProcessId Remissionsnummer
   * @returns Ergebnis des Remissionsabschlusses
   */
  protected abstract completeRemission(params: {
    remissionProcessId: number;
  }): Observable<boolean>;

  /**
   * Alle Remissionen abschließen
   * @param params.remissionProcessId Remissionsnummer
   * @returns Ergebnis des Remissionsabschlusses
   */
  abstract completeRemissions(params: {
    remissionProcessId: number;
  }): Observable<boolean>;

  /**
   * Abruf einer Remission
   * @param params.remissionProcessId Remissionsnummer
   * @returns Remissionsprozess
   */
  abstract getRemission(params: {
    remissionProcessId: number;
  }): Observable<RemissionProcess>;

  /**
   * Gibt anhand der remissionprocessId und der darin
   * definierten Einstellungen die Produktliste zurück
   * @param params param.remissionProcessId
   * @param params param.skip
   * @param params param.take
   * @returns Produktliste und Metainformationen (skip, take, completed)
   */
  abstract getRemissionProducts(params: {
    remissionProcessId: number;
  }): Observable<{
    skip?: number;
    take?: number;
    hits?: number;
    items: RemissionProduct[];
    completed: boolean;
  }>;

  /**
   * Aktualisieren der Remissions-Filter
   * @param changes.remissionProcessId Remissionsnummer
   * @param changes.changes Remissionsfilter
   * @returns Remissionsfilter
   */
  abstract updateRemissionFilter(changes: {
    remissionProcessId: number;
    changes: Partial<RemissionFilter>;
  }): Observable<RemissionFilter>;

  /**
   *  Abfrage ob für Remission Druckauftrag erforderlich
   * @param remissionProcessId Remissionsnummer
   * @returns Ob physischer Druck nötig
   */
  abstract isPrintingRequired(params: {
    remissionProcessId: number;
  }): Observable<boolean>;

  /**
   * Abfrage der verfügbaren Drucker
   * @returns Liste der verfügbaren Drucker
   */
  abstract getPrinters(): Observable<Printer[]>;

  /**
   * Druckauftrag für Remissionsliste
   * @param remissionProcessId Remissionsnummer
   * @param params.printerKey Name des Druckers
   * @returns Ob Druckauftrag ausgeführt wurde
   */
  abstract printRemissionList(params: {
    remissionProcessId: number;
    printerKey: string;
  }): Observable<boolean>;

  /**
   *  Druckauftrag für Warenbegleitschein
   * @param params.remissionProcessId Remissionsnummer
   * @param params.shippingDocumentId ID des Warenbegleitscheins (default: alle Warenbegleitscheine)
   * @param params.printerKey Name des Druckers
   * @returns Ob Druckauftrag ausgeführt wurde
   */
  abstract printShippingDocument(params: {
    remissionProcessId: number;
    shippingDocumentId?: number;
    printerKey: string;
  }): Observable<boolean>;

  /**
   * Produktsuche über EAN
   * @param ean Artikelidentifikationsnummer
   * @returns Produktinformation zur Artikelidentifikationsnummer
   */
  abstract searchProduct(params: { ean: string }): Observable<Product>;

  /**
   * Anwendbare Filter für die Suche
   * @param remissionSourceType Artikel-Ursprung (z.B. 'zentral')
   * @returns Mögliche Filteroptionen (inkl. Sub-gruppen)
   */
  abstract getFilters(params: {
    remissionProcessId: number;
  }): Observable<Filter[]>;

  /**
   * Arten der Produktplatzierung (z.B. Stapelplatz)
   * @returns Mögliche Platzierungen eines Produkts
   */
  abstract getPlacementTypes(): Observable<RemissionPlacementType[]>;

  /**
   * Gründe für Remission (z.B. beschädigtes Exemplar)
   * @returns Mögliche Gründe für Remission
   */
  abstract getRemissionReasons(): Observable<string[]>;

  /**
   * Remissions-Ziele / Lieferanten (z.B. Libri, Blank)
   * @returns Mägliche Remissions-Ziele
   */
  abstract getRemissionTargets(): Observable<RemissionSupplier[]>;

  /**
   * Artikel-Ursprung (z.B. zentrales Sortiment oder Überlauf)
   * @returns Mögliche Artikel-Ursprünge
   */
  abstract getRemissionSources(): Observable<RemissionSourceType[]>;

  /**
   * Abfrage der Kapazitätsauslastung
   * @returns Kapazitätsauslastung
   */
  abstract getCapacities(params: {
    selectedFilters?: { [filterId: string]: string[] };
    supplierId: number;
  }): Observable<CapacityType[]>;

  /**
   * Abruf eines Warenbegleitscheins (Shipping Documents)
   * @param params.remissionProcessId Remissionsnummer
   * @param params.shippingDocumentId ID des Warenbegleitscheins
   * @returns Warenbegleitscheins
   */
  abstract getShippingDocuments(params: {
    remissionProcessId: number;
    shippingDocumentId: number;
  }): Observable<ShippingDocument>;

  /**
   * Entfernen eiens Produkts von der Remissionsliste
   * @param input.remissionProcessId Remissionsnummer
   * @param input.product Remissionsprodukt
   * @returns Ob Produkt entfernt werden konnte
   */
  abstract deleteProductFromRemissionList(input: {
    remissionProcessId: number;
    remissionProductId: number;
  }): Observable<ActionResult<boolean>>;

  /**
   * Produkt der Remissionsliste hinzufügen
   * @param input.remissionProductId ID des hinzuzufügenden Produkts
   * @param input.remissionReason Remissionsgrund
   * @param input.remissionQuantity Anzahl der zur Remission hinzuzufügenden Exemplare
   * @returns Produktinformation über Remissionsprodukt
   */
  abstract addProductToRemit(input: {
    product: Product;
    remissionReason: string;
    remissionQuantity: number;
  }): Observable<RemissionProduct>;

  /**
   * Artikel zu Warenbegleitschein hinzufügen
   * @param params.remissionProcessId Remissionsnummer
   * @param params.remissionProductId ID des hinzuzufügenden Produkts
   * @param params.shippingDocumentId ID des Warenbegleitscheins
   * @param params.placementType Platzierungsart (z.B. Stapelplatz)
   * @param params.quantity Anzahl der zu hinzuzufügenden Exemplare
   * @returns Ob Artikel dem Warenbegleitschein hinzugefügt werden konnte
   */
  abstract addProductToShippingDocument(params: {
    remissionProcessId: number;
    remissionProductId: number;
    shippingDocumentId: number;
    placementType?: string;
    quantity?: number;
    inStock?: number;
    predefinedRemissionQuantity?: number;
  }): Observable<ActionResult<boolean>>;

  /**
   *  Artikel von Warenbegleitschein entfernen
   * @param params.remissionProcessId Remissionsnummer
   * @param params.shippingDocumentId ID des Warenbegleitscheins
   * @param params.remissionProductId ID des entfernenden Produkts
   * @param params.placementType Platzierungsart (default: alle)
   * @returns Ob Artikel vom  Warenbegleitschein entfernt werden konnte
   */
  abstract removeProductFromShippingDocument(params: {
    remissionProcessId: number;
    remissionProductId: number;
    shippingDocumentId: number;
    placementType?: string;
  }): Observable<boolean>;

  /**
   * Neuladen/Refresh der Remissions-Produkte (getRemission-Products Stream)
   * Beispiel: CtA 'Filtern" in Filter
   * @param params.remissionProcessId Remissionsnummer
   */
  abstract reloadProducts(params: { remissionProcessId: number }): void;

  /**
   * Warenbegleitschein abschließen
   * @param params.remissionProcessId Remissionsnummer
   * @param params.shippingDocumentId ID des Warenbegleitscheins
   * @param params.containerId Wannennummer
   * @returns Ob Warenbegleitschein abgeschlossen werden konnte
   */
  abstract completeShippingDocument(params: {
    remissionProcessId: number;
    shippingDocumentId: number;
    containerId: string;
  }): Observable<ActionResult<boolean>>;

  /**
   * Warenbegleitschein anlegen
   * @param params.remissionProcessId Remissionsprozess
   * @param params.shippingDocumentId PachstückId
   * @returns Neu erstellten Warenbegleitschein
   */
  abstract createShippingDocument(params: {
    remissionProcessId: number;
  }): Observable<ShippingDocument>;

  /**
   * Liste aller Remissionen
   */
  abstract getAllRemissions(params: {
    showOpen?: boolean;
    showOpenLastWeekOnly?: boolean;
    showCompleted?: boolean;
    showCompletedLastWeekOnly?: boolean;
    receiptNumber?: string;
    returnGroup?: number;
    take?: number;
  }): Observable<RemissionProcess[]>;

  /**
   * Liste nicht abgeschlossener Remissionen
   */
  abstract getUncompletedRemissions(): Observable<RemissionProcess[]>;

  /**
   * Remission abbrechen
   */
  abstract deleteRemission(params: {
    remissionProcessId: number;
    externalId?: number;
  }): Observable<boolean>;

  abstract deleteShippingDocument(params: {
    remissionProcessId: number;
    shippingDocumentId: number;
    externalId?: number;
  }): Observable<
    ActionResult<{ deleted: boolean; completedRemissionsExist: boolean }>
  >;
}
