<?php

declare(strict_types=1);

namespace app\common\service;

/**
 * 分流链接像素配置：解析、校验、合并保存、脱敏
 */
class SplitPixelConfigService
{
    public const PLATFORM_FACEBOOK = 'facebook';

    public const PLATFORM_TIKTOK = 'tiktok';

    /** @var string[] */
    public const EVENT_OPTIONS = [
        'PageView',
        'Lead',
        'Contact',
        'AddToCart',
        'Purchase',
        'Subscribe',
    ];

    private const MAX_ITEMS_PER_PLATFORM = 20;

    /**
     * 解析存储 JSON 为规范结构
     *
     * @return array{facebook: array<int, array<string, mixed>>, tiktok: array<int, array<string, mixed>>}
     */
    public static function parseStorage(?string $raw): array
    {
        $empty = [
            self::PLATFORM_FACEBOOK => [],
            self::PLATFORM_TIKTOK   => [],
        ];
        if ($raw === null || trim($raw) === '') {
            return $empty;
        }
        $decoded = json_decode($raw, true);
        if (!is_array($decoded)) {
            return $empty;
        }

        return [
            self::PLATFORM_FACEBOOK => self::normalizePlatformList(
                $decoded[self::PLATFORM_FACEBOOK] ?? [],
                self::PLATFORM_FACEBOOK
            ),
            self::PLATFORM_TIKTOK => self::normalizePlatformList(
                $decoded[self::PLATFORM_TIKTOK] ?? [],
                self::PLATFORM_TIKTOK
            ),
        ];
    }

    /**
     * 合并 POST 数据与已有配置（Token / 测试码留空保留原值）
     *
     * @param array<string, mixed> $incoming
     * @param array<string, mixed> $existing
     * @return array{facebook: array<int, array<string, mixed>>, tiktok: array<int, array<string, mixed>>}
     */
    public static function mergeForSave(array $incoming, array $existing): array
    {
        $existingMap = self::indexById($existing);
        $result = [
            self::PLATFORM_FACEBOOK => [],
            self::PLATFORM_TIKTOK   => [],
        ];

        foreach ([self::PLATFORM_FACEBOOK, self::PLATFORM_TIKTOK] as $platform) {
            $rows = is_array($incoming[$platform] ?? null) ? $incoming[$platform] : [];
            if (count($rows) > self::MAX_ITEMS_PER_PLATFORM) {
                throw new \InvalidArgumentException('像素配置数量超出上限');
            }
            foreach ($rows as $row) {
                if (!is_array($row)) {
                    continue;
                }
                $normalized = self::normalizeRow($row, $platform);
                $id = (string) ($normalized['id'] ?? '');
                if ($id !== '' && isset($existingMap[$id])) {
                    $old = $existingMap[$id];
                if (trim((string) ($normalized['access_token'] ?? '')) === ''
                    || strpos((string) ($normalized['access_token'] ?? ''), '***') !== false) {
                    $normalized['access_token'] = (string) ($old['access_token'] ?? '');
                }
                    if (trim((string) ($normalized['test_code'] ?? '')) === '') {
                        $normalized['test_code'] = (string) ($old['test_code'] ?? '');
                    }
                }
                if (trim((string) ($normalized['pixel_id'] ?? '')) === '') {
                    continue;
                }
                $result[$platform][] = $normalized;
            }
            usort($result[$platform], static function (array $a, array $b): int {
                return ((int) ($a['sort'] ?? 0)) <=> ((int) ($b['sort'] ?? 0));
            });
        }

        return $result;
    }

    /**
     * @param array{facebook: array<int, array<string, mixed>>, tiktok: array<int, array<string, mixed>>} $config
     */
    public static function encodeStorage(array $config): string
    {
        $payload = [
            self::PLATFORM_FACEBOOK => $config[self::PLATFORM_FACEBOOK] ?? [],
            self::PLATFORM_TIKTOK   => $config[self::PLATFORM_TIKTOK] ?? [],
        ];

        return json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: '{}';
    }

    /**
     * 管理端 GET：脱敏 access_token
     *
     * @param array{facebook: array<int, array<string, mixed>>, tiktok: array<int, array<string, mixed>>} $config
     * @return array{facebook: array<int, array<string, mixed>>, tiktok: array<int, array<string, mixed>>}
     */
    public static function maskForAdmin(array $config): array
    {
        $mask = static function (array $rows): array {
            $out = [];
            foreach ($rows as $row) {
                $item = $row;
                $token = (string) ($item['access_token'] ?? '');
                $item['access_token'] = $token === '' ? '' : self::maskToken($token);
                $item['has_access_token'] = $token !== '';
                unset($item['access_token_raw']);
                $out[] = $item;
            }

            return $out;
        };

        return [
            self::PLATFORM_FACEBOOK => $mask($config[self::PLATFORM_FACEBOOK] ?? []),
            self::PLATFORM_TIKTOK   => $mask($config[self::PLATFORM_TIKTOK] ?? []),
        ];
    }

    /**
     * 获取已启用且按 sort 排序的条目（中转页 / 服务端回传）
     *
     * @param array{facebook: array<int, array<string, mixed>>, tiktok: array<int, array<string, mixed>>} $config
     * @return array<int, array<string, mixed>>
     */
    public static function getEnabledSorted(array $config, string $platform): array
    {
        $rows = $config[$platform] ?? [];
        $enabled = [];
        foreach ($rows as $row) {
            if ((int) ($row['enabled'] ?? 0) === 1) {
                $enabled[] = $row;
            }
        }
        usort($enabled, static function (array $a, array $b): int {
            return ((int) ($a['sort'] ?? 0)) <=> ((int) ($b['sort'] ?? 0));
        });

        return $enabled;
    }

    public static function maskToken(string $token): string
    {
        $len = strlen($token);
        if ($len <= 8) {
            return '***';
        }

        return substr($token, 0, 3) . '***' . substr($token, -3);
    }

    /**
     * @param array<int, array<string, mixed>> $rows
     * @return array<int, array<string, mixed>>
     */
    private static function normalizePlatformList(array $rows, string $platform): array
    {
        $result = [];
        foreach ($rows as $row) {
            if (!is_array($row)) {
                continue;
            }
            $normalized = self::normalizeRow($row, $platform);
            if (trim((string) ($normalized['pixel_id'] ?? '')) === '') {
                continue;
            }
            $result[] = $normalized;
        }
        usort($result, static function (array $a, array $b): int {
            return ((int) ($a['sort'] ?? 0)) <=> ((int) ($b['sort'] ?? 0));
        });

        return $result;
    }

    /**
     * @param array<string, mixed> $row
     * @return array<string, mixed>
     */
    private static function normalizeRow(array $row, string $platform): array
    {
        $event = (string) ($row['event'] ?? 'PageView');
        if (!in_array($event, self::EVENT_OPTIONS, true)) {
            $event = 'PageView';
        }
        $id = trim((string) ($row['id'] ?? ''));
        if ($id === '') {
            $id = $platform . '_' . uniqid('', true);
        }

        return [
            'id'              => $id,
            'enabled'         => (int) ($row['enabled'] ?? 0) === 1 ? 1 : 0,
            'server_postback' => (int) ($row['server_postback'] ?? 0) === 1 ? 1 : 0,
            'pixel_id'        => trim((string) ($row['pixel_id'] ?? '')),
            'access_token'    => trim((string) ($row['access_token'] ?? '')),
            'test_code'       => trim((string) ($row['test_code'] ?? '')),
            'event'           => $event,
            'sort'            => max(0, (int) ($row['sort'] ?? 0)),
        ];
    }

    /**
     * @param array{facebook: array<int, array<string, mixed>>, tiktok: array<int, array<string, mixed>>} $config
     * @return array<string, array<string, mixed>>
     */
    private static function indexById(array $config): array
    {
        $map = [];
        foreach ([self::PLATFORM_FACEBOOK, self::PLATFORM_TIKTOK] as $platform) {
            foreach ($config[$platform] ?? [] as $row) {
                $id = (string) ($row['id'] ?? '');
                if ($id !== '') {
                    $map[$id] = $row;
                }
            }
        }

        return $map;
    }
}
