# PP Customization Engine

Headless interpreter kontraktu CustomizationContract -- zunifikowanej schemy dostrajania ofert ubezpieczeniowych.

## Instalacja

```bash
npm install pp-customization-engine
```

## Czym jest CustomizationContract?

Worker ubezpieczeniowy zwraca `CustomizationContract` zawierający:
- **dataSchema** -- JSON Schema (draft 2020-12) opisujący strukturę danych, typy i walidację
- **uiSchema** -- format opisujący prezentację formularza: kategorie, elementy, widgety, reguły widoczności
- **values** -- aktualne wartości pól formularza
- **messages** -- opcjonalne komunikaty biznesowe
- **variantOverrides** -- opcjonalna deklaracja wariantów (patrz niżej)

### variantOverrides -- przełączanie pakietów

`variantOverrides` to opcjonalny mechanizm dla ofert, które dzielą zestaw pól na rozłączne **warianty** (np. pakiet podstawowy / standardowy / premium). Każdy wariant ma własny domyślny zestaw pól (które ryzyka są domyślnie zaznaczone, jakie sumy są domyślne itd.).

Schemat:

```typescript
{
  variantOverrides: {
    discriminatorScope: "variant",          // pole sterujące wyborem wariantu
    defaultsByValue: {
      "PACKAGE_BASIC":   { risk_THEFT: false, risk_FIRE: true,  risk_FLOOD: false, risk_FIRE_sum: 100000 },
      "PACKAGE_STANDARD":{ risk_THEFT: true,  risk_FIRE: true,  risk_FLOOD: false, risk_FIRE_sum: 200000 },
      "PACKAGE_PREMIUM": { risk_THEFT: true,  risk_FIRE: true,  risk_FLOOD: true,  risk_FIRE_sum: 500000 }
    }
  }
}
```

Gdy użytkownik zmieni wartość pola `discriminatorScope` (tutaj `variant`), silnik automatycznie nadpisze wszystkie pola wymienione w `defaultsByValue[nowyWariant]` ich nowymi wartościami domyślnymi. To jest **hard reset** -- jeśli użytkownik wcześniej zmienił którekolwiek z pól ujętych w `defaultsByValue`, jego modyfikacje zostaną zastąpione domyślnymi wartościami nowego wariantu.

Workery ubezpieczycieli, którzy nie mają wariantów (np. swobodna lista ryzyk do wyboru), nie ustawiają `variantOverrides`. Silnik zachowuje się wtedy bez zmian -- żadnego resetu, żadnego dodatkowego kosztu.

To worker decyduje, jak nazwać `discriminatorScope` i co umieścić w `defaultsByValue`. Silnik nie ma wbudowanej wiedzy o konkretnych wariantach żadnego ubezpieczyciela.

## Użycie

```typescript
import { CustomizationEngine } from 'pp-customization-engine';

const engine = new CustomizationEngine(contractFromWorker);

// Odpytaj silnik o stan pola
const fieldState = engine.getFieldState('acType');
// fieldState.visible, fieldState.disabled, fieldState.options, fieldState.errors, fieldState.widgetType

// Zmień wartość pola
const result = engine.setValue('ac', 'no');
// result.changedFields, result.resetFields, result.validationResult

// Pobierz badge'e błędów per zakładka
const badges = engine.getCategoryErrorCounts();
// { risks: 0, discounts: 1, payment: 0 }

// Sprawdź czy formularz jest zmodyfikowany
engine.isDirty(); // true/false

// Po przeliczeniu przez worker -- zaktualizuj kontrakt
engine.updateContract(newContractFromWorker);
```

## Architektura

Silnik jest **framework-agnostic** -- nie zależy od Angulara, Reacta ani żadnego innego frameworka UI.

Każdy projekt frontowy dostarcza własne widgety/komponenty i używa silnika do odpowiedzi na pytania:
- Czy pole jest widoczne? -> `engine.getFieldState(scope).visible`
- Jakie opcje ma pole? -> `engine.getFieldState(scope).options`
- Jakie błędy walidacji? -> `engine.getFieldState(scope).errors`
- Jaki widget użyć? -> `engine.getFieldState(scope).widgetType`

## Rozwój

```bash
npm install
npm test
npm run build
npm run lint
```

## Licencja

MIT
