# Advanced Banners

Advanced Banners let you define responsive, context-aware banner ad layouts that adapt to device type, screen orientation, and screen size. Unlike regular banners (which support only top/bottom positioning), Advanced Banners allow you to place multiple banners at arbitrary positions on the screen and automatically switch layouts when conditions change.

### Checking Support

```csharp
if (Bridge.advertisement.isAdvancedBannersSupported)
{
    // Advanced Banners are available
}
```

### Usage

#### Method 1: Explicit API Call

Show and hide Advanced Banners directly from your game code:

```csharp
// Show banners for a specific placement
Bridge.advertisement.ShowAdvancedBanners("main_menu");

// Hide banners
Bridge.advertisement.HideAdvancedBanners();
```

If `placementFallback` is set in the config, you can call without arguments:

```csharp
Bridge.advertisement.ShowAdvancedBanners();
```

#### Method 2: Automatic via Platform Messages

Advanced Banners automatically react to platform messages. When you call `Bridge.platform.SendMessage()` or `Bridge.platform.SendCustomMessage()`, the system checks if a matching placement exists in the config and triggers it.

```csharp
// This will automatically show banners if "level_paused" placement is configured
Bridge.platform.SendMessage(PlatformMessage.LevelPaused);

// This will hide banners if "level_resumed" has action: "hide"
Bridge.platform.SendMessage(PlatformMessage.LevelResumed);

// Custom messages work the same way
Bridge.platform.SendCustomMessage("shop_opened");
```

This is the recommended approach because it ties banner visibility to your game's lifecycle without extra code.

#### Tracking State

```csharp
// Check current state
BannerState state = Bridge.advertisement.advancedBannersState;
// Possible values: BannerState.Loading, BannerState.Shown, BannerState.Hidden, BannerState.Failed

// Listen for state changes
Bridge.advertisement.advancedBannersStateChanged += OnAdvancedBannersStateChanged;

private void OnAdvancedBannersStateChanged(BannerState state)
{
    switch (state)
    {
        case BannerState.Loading:
            // Banners are being loaded
            break;
        case BannerState.Shown:
            // Banners are visible
            break;
        case BannerState.Hidden:
            // Banners were hidden
            break;
        case BannerState.Failed:
            // Banners failed to load
            break;
    }
}
```

Don't forget to unsubscribe when no longer needed:

```csharp
Bridge.advertisement.advancedBannersStateChanged -= OnAdvancedBannersStateChanged;
```

### Automatic Behavior

#### Fullscreen Ad Coordination

Advanced Banners are automatically hidden when an interstitial or rewarded ad starts (loading or opened) and automatically restored when the ad finishes (closed or failed). No additional code is needed.

```
Interstitial starts → Advanced Banners hidden
Interstitial ends   → Advanced Banners restored

Rewarded starts     → Advanced Banners hidden
Rewarded ends       → Advanced Banners restored
```

#### Responsive Re-evaluation

When the screen orientation changes or the window is resized, the system automatically re-evaluates conditions and switches to a better-matching variant if one exists. This happens with a 200ms debounce to avoid excessive updates.

For example, if a user rotates their phone from portrait to landscape, and your config has different layouts for each orientation, the banners will seamlessly switch.

### Complete Example

#### Config

```json
{
    "advertisement": {
        "advancedBanners": {
            "placementFallback": "gameplay_stopped",
            "gameplay_started": {
                "action": "hide"
            },
            "gameplay_stopped": {
                "action": "show",
                "default": [
                    { "width": "300px", "height": "250px", "bottom": "10%", "right": "5%" }
                ],
                "mobile:portrait": [
                    { "width": "320px", "height": "50px", "bottom": "0", "left": "0" }
                ],
                "mobile:landscape": [
                    { "width": "300px", "height": "250px", "top": "50%", "right": "0" }
                ],
                "desktop:w>1200": [
                    { "width": "160px", "height": "600px", "top": "10%", "left": "1%" },
                    { "width": "160px", "height": "600px", "top": "10%", "right": "1%" }
                ],
                "desktop:w<=1200": [
                    { "width": "728px", "height": "90px", "bottom": "0", "left": "50%" }
                ],
                "desktop:landscape:ar>=1.78": [
                    { "width": "200px", "height": "600px", "top": "5%", "left": "0" },
                    { "width": "200px", "height": "600px", "top": "5%", "right": "0" },
                    { "width": "970px", "height": "90px", "bottom": "0", "left": "50%" }
                ]
            },
            "<your_placement_here>": {
                "default": [
                    { "width": "728px", "height": "90px", "bottom": "0", "left": "50%" }
                ]
            },
            "<your_placement_here>": {
                "action": "hide"
            }
        }
    }
}
```

#### Game Code

```csharp
using Playgama;
using Playgama.Modules.Advertisement;
using Playgama.Modules.Platform;

public class AdManager : MonoBehaviour
{
    private void Start()
    {
        Bridge.advertisement.advancedBannersStateChanged += OnAdvancedBannersStateChanged;
    }

    public void OnGameplayStarted()
    {
        // Hides banners automatically via config
        Bridge.platform.SendMessage(PlatformMessage.GameplayStarted);
    }

    public void OnGameplayStopped()
    {
        // Shows banners automatically (best layout auto-selected)
        Bridge.platform.SendMessage(PlatformMessage.GameplayStopped);
    }

    public void OnShopOpened()
    {
        // Custom messages work the same way
        Bridge.platform.SendCustomMessage("your_placement_here");
    }

    public void OnShopClosed()
    {
        Bridge.platform.SendCustomMessage("your_placement_here");
    }

    public void ShowBannersDirectly()
    {
        // Or call directly
        Bridge.advertisement.ShowAdvancedBanners("gameplay_stopped");
    }

    public void HideBannersDirectly()
    {
        Bridge.advertisement.HideAdvancedBanners();
    }

    private void OnAdvancedBannersStateChanged(BannerState state)
    {
        Debug.Log($"Advanced Banners: {state}");
    }

    private void OnDestroy()
    {
        Bridge.advertisement.advancedBannersStateChanged -= OnAdvancedBannersStateChanged;
    }
}
```

### Configuration

Advanced Banners are configured in `playgama-bridge-config.json` under `advertisement.advancedBanners`.

```json
{
    "advertisement": {
        "advancedBanners": {
            "disable": false,
            "placementFallback": "main_menu",
            "main_menu": {
                "default": [
                    { "width": "300px", "height": "250px", "top": "10%", "right": "10%" }
                ]
            },
            "level_paused": {
                "action": "show",
                "default": [
                    { "width": "300px", "height": "250px", "top": "10%", "right": "10%" }
                ],
                "mobile:portrait": [
                    { "width": "100%", "height": "80px", "bottom": "0", "left": "0" }
                ],
                "desktop:landscape:w>1200": [
                    { "width": "160px", "height": "600px", "top": "10%", "left": "2%" },
                    { "width": "160px", "height": "600px", "top": "10%", "right": "2%" }
                ]
            },
            "level_resumed": {
                "action": "hide"
            }
        }
    }
}
```

#### General Options

| Parameter           | Type    | Default | Description                                                                         |
| ------------------- | ------- | ------- | ----------------------------------------------------------------------------------- |
| `disable`           | boolean | `false` | Disable Advanced Banners entirely, even if the platform supports them               |
| `placementFallback` | string  | —       | Default placement to use when `ShowAdvancedBanners()` is called without an argument |

#### Placement Configuration

Each key under `advancedBanners` (other than `disable` and `placementFallback`) defines a **placement**. A placement is identified by a string that matches either:

* A built-in platform message (e.g. `game_ready`, `level_paused`, `gameplay_started`)
* A custom message ID passed to `SendCustomMessage()`
* A string passed directly to `ShowAdvancedBanners()`

Each placement contains:

| Property        | Type                 | Default  | Description                                                               |
| --------------- | -------------------- | -------- | ------------------------------------------------------------------------- |
| `action`        | `"show"` \| `"hide"` | `"show"` | Whether to show or hide banners when this placement is triggered          |
| `default`       | array                | —        | Fallback banner layout when no condition-based variant matches            |
| *condition key* | array                | —        | Banner layout for a specific set of conditions (see Condition Keys below) |

#### Banner Object

Each banner in the array is an object with CSS positioning values:

| Property | Type   | Description                           |
| -------- | ------ | ------------------------------------- |
| `width`  | string | CSS width (e.g. `"300px"`, `"100%"`)  |
| `height` | string | CSS height (e.g. `"250px"`, `"80px"`) |
| `top`    | string | CSS top offset (e.g. `"0"`, `"10%"`)  |
| `bottom` | string | CSS bottom offset                     |
| `left`   | string | CSS left offset                       |
| `right`  | string | CSS right offset                      |

You can define multiple banners per variant to show several ads simultaneously:

```json
"desktop:landscape": [
    { "width": "160px", "height": "600px", "top": "10%", "left": "2%" },
    { "width": "160px", "height": "600px", "top": "10%", "right": "2%" },
    { "width": "728px", "height": "90px", "bottom": "0", "left": "50%" }
]
```

### Condition Keys

Condition keys are colon-separated segments that describe when a variant should be used. The system evaluates all keys against the current environment and picks the best match.

#### Available Segments

| Segment          | Example                             | Description                                                                                                                          |
| ---------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Device type      | `mobile`, `desktop`, `tablet`, `tv` | Matches the current device type                                                                                                      |
| Orientation      | `portrait`, `landscape`             | Matches the current screen orientation                                                                                               |
| Width condition  | `w>600`, `w<=1024`, `w>=768`        | Matches against window width (or canvas width if `canvas` segment is present)                                                        |
| Height condition | `h>400`, `h<=900`                   | Matches against window height (or canvas height)                                                                                     |
| Aspect ratio     | `ar>1.5`, `ar>=1.78`, `ar<=1.0`     | Matches screen width/height ratio                                                                                                    |
| Canvas mode      | `canvas`                            | Use game canvas dimensions instead of window size for all `w`/`h`/`ar` conditions. If no canvas is found, the variant will not match |

#### Combining Segments

Combine segments with `:` to create compound conditions. All segments must match for the variant to be selected:

```json
{
    "mobile:portrait": [...],
    "mobile:portrait:w>400": [...],
    "desktop:landscape:w>1200:ar>=1.5": [...],
    "tablet:canvas:w>800": [...]
}
```

#### Priority Scoring

When multiple variants match, the one with the highest score wins:

| Segment Type                            | Score |
| --------------------------------------- | ----- |
| Device type (`mobile`, `desktop`, etc.) | +4    |
| Orientation (`portrait`, `landscape`)   | +2    |
| Canvas mode (`canvas`)                  | +1    |
| Each dimension/aspect ratio condition   | +1    |

If two variants have the same score, the one with **more segments** wins. If they also have the same number of segments, the one whose dimension/aspect ratio threshold is **closest to the actual value** takes priority.

**Example**: screen is 1300px wide, device is desktop

| Key                        | Matches?       | Score                        |
| -------------------------- | -------------- | ---------------------------- |
| `default`                  | yes (fallback) | -1                           |
| `desktop`                  | yes            | 4                            |
| `desktop:w>500`            | yes            | 4 + 1 = 5                    |
| `desktop:w>1200`           | yes            | 5 + higher specificity bonus |
| `desktop:landscape:w>1200` | yes            | 4 + 2 + 1 = 7                |
| `mobile:portrait`          | no             | —                            |
