# API

## Scope

Dokument opisuje aktualne REST API dostepne przez `api.php` (ordersPRO + slowniki + produkty + kategorie).

## Base URL

- Endpoint techniczny: `/api.php`
- Routing odbywa sie przez query params:
  - `endpoint` (np. `orders`, `products`)
  - `action` (np. `list`, `get`)

Przyklad:

```text
GET /api.php?endpoint=orders&action=list
```

## Authentication

- Wymagany naglowek: `X-Api-Key: <api_key>`
- Klucz jest porownywany z wartoscia `pp_settings.api_key`
- Brak lub zly klucz:
  - HTTP `401`
  - payload:
    ```json
    {
      "status": "error",
      "code": "UNAUTHORIZED",
      "message": "Invalid or missing API key"
    }
    ```

## Response format

Sukces:

```json
{
  "status": "ok",
  "data": {}
}
```

Blad:

```json
{
  "status": "error",
  "code": "BAD_REQUEST",
  "message": "..."
}
```

## Common HTTP/logic errors

- `400 BAD_REQUEST` - brak wymaganych parametrow/body
- `401 UNAUTHORIZED` - brak/zly API key
- `404 NOT_FOUND` - nieznany endpoint/action lub brak rekordu
- `405 METHOD_NOT_ALLOWED` - zla metoda HTTP
- `500 INTERNAL_ERROR` - blad serwera

## Endpoints

### Orders (`endpoint=orders`)

- `GET action=list`
  - filtry (opcjonalne): `status`, `paid`, `date_from`, `date_to`, `updated_since`, `number`, `client`
  - paginacja: `page` (default 1), `per_page` (default 50, max 100)
- `GET action=get&id={id}`
- `PUT action=change_status&id={id}`
  - body JSON:
    - `status_id` (required, int)
    - `send_email` (optional, bool)
- `PUT action=set_paid&id={id}`
  - body JSON optional: `send_email` (bool)
- `PUT action=set_unpaid&id={id}`

### Products (`endpoint=products`)

- `GET action=list`
  - filtry:
    - `search`, `status`, `promoted`
    - `attribute_{attributeId}={valueId}` (np. `attribute_12=37`)
  - sortowanie: `sort` (default `id`), `sort_dir` (default `DESC`)
  - paginacja: `page`, `per_page` (max 100)
- `GET action=get&id={id}`
- `POST action=create`
  - wymagane minimum:
    - `languages` (array, co najmniej jeden jezyk z `name`)
    - `price_brutto` (number >= 0)
- `PUT action=update&id={id}`
  - partial update przez JSON body
- `GET action=variants&id={parentProductId}`
  - dla produktu glownego (nie wariantu)
- `POST action=create_variant&id={parentProductId}`
  - body:
    - `attributes` (required array)
    - opcjonalnie pola wariantu (np. `price_brutto`, `quantity`, `sku`, ...)
- `PUT action=update_variant&id={variantId}`
  - partial update wariantu
- `DELETE action=delete_variant&id={variantId}`
- `POST action=upload_image`
  - body:
    - `id` (product id, required)
    - `file_name` (required)
    - `content_base64` (required)
    - `alt` (optional)
    - `o` (optional position)

### Dictionaries (`endpoint=dictionaries`)

- `GET action=statuses`
- `GET action=transports`
- `GET action=payment_methods`
- `GET action=attributes`
- `POST action=ensure_attribute`
  - body: `name` (required), `type` (optional int), `lang` (optional, default `pl`)
- `POST action=ensure_attribute_value`
  - body: `attribute_id` (required), `name` (required), `lang` (optional, default `pl`)
- `POST action=ensure_producer`
  - body: `name` (required)

### Categories (`endpoint=categories`)

- `GET action=list`
  - zwraca aktywne kategorie w formie flat list:
    - `id`
    - `parent_id`
    - `title`
  - tytuly pobierane najpierw w jezyku domyslnym (`pp_langs.start=1`), potem fallback.

## Source of truth (mapa API w kodzie)

### 1) Wejscie i dispatch

- `api.php`
  - wykrywa request API przez `$_GET['endpoint']`
  - ustawia JSON content-type
  - tworzy `medoo` + `SettingsRepository`
  - przekazuje sterowanie do `\api\ApiRouter::handle()`
- `autoload/api/ApiRouter.php`
  - autentykacja (`X-Api-Key` vs `pp_settings.api_key`)
  - walidacja `endpoint` i `action`
  - mapowanie endpoint -> kontroler (`getControllerFactories()`)
  - helpery odpowiedzi: `sendSuccess()`, `sendError()`
  - helpery requestu: `getJsonBody()`, `requireMethod()`

### 2) Endpointy i kontrolery (runtime source)

#### `endpoint=orders`

- plik: `autoload/api/Controllers/OrdersApiController.php`
- akcje:
  - `list` (GET)
  - `get` (GET)
  - `change_status` (PUT)
  - `set_paid` (PUT)
  - `set_unpaid` (PUT)

#### `endpoint=products`

- plik: `autoload/api/Controllers/ProductsApiController.php`
- akcje:
  - `list` (GET)
  - `get` (GET)
  - `create` (POST)
  - `update` (PUT)
  - `variants` (GET)
  - `create_variant` (POST)
  - `update_variant` (PUT)
  - `delete_variant` (DELETE)
  - `upload_image` (POST)

#### `endpoint=dictionaries`

- plik: `autoload/api/Controllers/DictionariesApiController.php`
- akcje:
  - `statuses` (GET)
  - `transports` (GET)
  - `payment_methods` (GET)
  - `attributes` (GET)
  - `ensure_attribute` (POST)
  - `ensure_attribute_value` (POST)
  - `ensure_producer` (POST)

#### `endpoint=categories`

- plik: `autoload/api/Controllers/CategoriesApiController.php`
- akcje:
  - `list` (GET)

### 3) Warstwa domenowa pod API (shape danych)

- Orders:
  - `Domain\Order\OrderRepository::listForApi()`
  - `Domain\Order\OrderRepository::findForApi()`
  - `Domain\Order\OrderAdminService` (zmiana statusu/platnosci)
- Products:
  - `Domain\Product\ProductRepository::listForApi()`
  - `Domain\Product\ProductRepository::findForApi()`
  - `Domain\Product\ProductRepository::saveProduct()`
  - metody wariantow `*VariantForApi()`
- Dictionaries:
  - `Domain\ShopStatus\ShopStatusRepository`
  - `Domain\Transport\TransportRepository`
  - `Domain\PaymentMethod\PaymentMethodRepository`
  - `Domain\Attribute\AttributeRepository`
  - `Domain\Producer\ProducerRepository`
- Categories:
  - bezposrednio query przez `$GLOBALS['mdb']` w `CategoriesApiController`

### 4) Testy API (behavior source)

- `tests/Unit/api/ApiRouterTest.php`
- `tests/Unit/api/Controllers/OrdersApiControllerTest.php`
- `tests/Unit/api/Controllers/ProductsApiControllerTest.php`
- `tests/Unit/api/Controllers/DictionariesApiControllerTest.php`

### 5) Dokumentacja kontraktu (human source)

- `api-docs/api-reference.json`
- `api-docs/index.html`

Uwaga: dokumentacja z `api-docs/*` moze byc starsza od runtime.
Zrodlem prawdy dla dzialania endpointow jest zawsze:
`api.php` + `autoload/api/ApiRouter.php` + aktualne kontrolery `autoload/api/Controllers/*`.

## Curl examples

Pobranie listy zamowien:

```bash
curl -X GET "https://example.com/api.php?endpoint=orders&action=list&page=1&per_page=20" \
  -H "X-Api-Key: YOUR_API_KEY"
```

Zmiana statusu zamowienia:

```bash
curl -X PUT "https://example.com/api.php?endpoint=orders&action=change_status&id=123" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"status_id\": 6, \"send_email\": true}"
```

Dodanie wariantu produktu:

```bash
curl -X POST "https://example.com/api.php?endpoint=products&action=create_variant&id=50" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"attributes\":[{\"attribute_id\":12,\"attribute_value_id\":37}],\"price_brutto\":99.99,\"quantity\":10}"
```
