<?php

namespace App\Services\Paddle;

use App\Models\Package;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

class PaddleCatalogService
{
    public function __construct(private readonly PaddleClient $client) {}

    /**
     * @return array<string, mixed>
     */
    public function fetchProduct(string $productId): array
    {
        return $this->extractEntity($this->client->get("/products/{$productId}"));
    }

    /**
     * @return array<string, mixed>
     */
    public function fetchPrice(string $priceId): array
    {
        return $this->extractEntity($this->client->get("/prices/{$priceId}"));
    }

    /**
     * @return array<string, mixed>
     */
    public function createProduct(Package $package, array $overrides = []): array
    {
        $payload = $this->buildProductPayload($package, $overrides);

        return $this->extractEntity($this->client->post('/products', $payload));
    }

    /**
     * @return array<string, mixed>
     */
    public function updateProduct(string $productId, Package $package, array $overrides = []): array
    {
        $payload = $this->buildProductPayload($package, $overrides);

        return $this->extractEntity($this->client->patch("/products/{$productId}", $payload));
    }

    /**
     * @return array<string, mixed>
     */
    public function createPrice(Package $package, string $productId, array $overrides = []): array
    {
        $payload = $this->buildPricePayload($package, $productId, $overrides, includeProduct: true);

        return $this->extractEntity($this->client->post('/prices', $payload));
    }

    /**
     * @return array<string, mixed>
     */
    public function updatePrice(string $priceId, Package $package, array $overrides = []): array
    {
        $payload = $this->buildPricePayload(
            $package,
            $overrides['product_id'] ?? $package->paddle_product_id,
            $overrides,
            includeProduct: false
        );

        return $this->extractEntity($this->client->patch("/prices/{$priceId}", $payload));
    }

    /**
     * @return array<string, mixed>
     */
    public function buildProductPayload(Package $package, array $overrides = []): array
    {
        $payload = array_merge([
            'name' => $this->resolveName($package, $overrides),
            'description' => $this->resolveDescription($package, $overrides),
            'tax_category' => $overrides['tax_category'] ?? 'standard',
            'type' => $overrides['type'] ?? 'standard',
            'custom_data' => $this->buildCustomData($package, $overrides['custom_data'] ?? []),
        ], Arr::except($overrides, ['tax_category', 'type', 'custom_data']));

        return $this->cleanPayload($payload);
    }

    /**
     * @return array<string, mixed>
     */
    public function buildPricePayload(Package $package, string $productId, array $overrides = [], bool $includeProduct = true): array
    {
        $unitPrice = $overrides['unit_price'] ?? [
            'amount' => (string) $this->priceToMinorUnits($package->price),
            'currency_code' => Str::upper((string) ($package->currency ?? 'EUR')),
        ];

        $base = [
            'description' => $this->resolvePriceDescription($package, $overrides),
            'unit_price' => $unitPrice,
            'custom_data' => $this->buildCustomData($package, $overrides['custom_data'] ?? []),
        ];

        if ($includeProduct) {
            $base['product_id'] = $productId;
        }

        $payload = array_merge($base, Arr::except($overrides, ['unit_price', 'description', 'custom_data', 'product_id']));

        return $this->cleanPayload($payload);
    }

    /**
     * @param  array<string, mixed>  $response
     * @return array<string, mixed>
     */
    protected function extractEntity(array $response): array
    {
        return Arr::get($response, 'data', $response);
    }

    /**
     * @param  array<string, mixed>  $payload
     * @return array<string, mixed>
     */
    protected function cleanPayload(array $payload): array
    {
        $filtered = collect($payload)
            ->reject(static fn ($value) => $value === null || $value === '' || $value === [])
            ->all();

        if (array_key_exists('custom_data', $filtered)) {
            $filtered['custom_data'] = collect($filtered['custom_data'])
                ->reject(static fn ($value) => $value === null || $value === '' || $value === [])
                ->all();
        }

        return $filtered;
    }

    /**
     * @param  array<string, mixed>  $extra
     * @return array<string, mixed>
     */
    protected function buildCustomData(Package $package, array $extra = []): array
    {
        $base = [
            'fotospiel_package_id' => (string) $package->id,
            'slug' => $package->slug,
            'type' => $package->type,
            'features' => $package->features,
            'limits' => array_filter([
                'max_photos' => $package->max_photos,
                'max_guests' => $package->max_guests,
                'gallery_days' => $package->gallery_days,
                'max_tasks' => $package->max_tasks,
                'max_events_per_year' => $package->max_events_per_year,
            ], static fn ($value) => $value !== null),
            'translations' => array_filter([
                'name' => $package->name_translations,
                'description' => $package->description_translations,
            ], static fn ($value) => ! empty($value)),
        ];

        return array_merge($base, $extra);
    }

    protected function resolveName(Package $package, array $overrides): string
    {
        if (isset($overrides['name']) && is_string($overrides['name'])) {
            return $overrides['name'];
        }

        if (! empty($package->name)) {
            return $package->name;
        }

        $translations = $package->name_translations ?? [];

        return $translations['en'] ?? $translations['de'] ?? $package->slug;
    }

    protected function resolveDescription(Package $package, array $overrides): string
    {
        if (array_key_exists('description', $overrides)) {
            $value = is_string($overrides['description']) ? trim($overrides['description']) : null;

            if ($value !== null && $value !== '') {
                return $value;
            }
        }

        if (! empty($package->description)) {
            return strip_tags((string) $package->description);
        }

        $translations = $package->description_translations ?? [];

        $fallback = $translations['en'] ?? $translations['de'] ?? null;

        if ($fallback !== null) {
            $fallback = trim(strip_tags((string) $fallback));
            if ($fallback !== '') {
                return $fallback;
            }
        }

        return sprintf('Fotospiel package %s', $package->slug ?? $package->id);
    }

    /**
     * @param  array<string, mixed>  $overrides
     */
    protected function resolvePriceDescription(Package $package, array $overrides): string
    {
        if (array_key_exists('description', $overrides)) {
            $value = is_string($overrides['description']) ? trim($overrides['description']) : null;

            if ($value !== null && $value !== '') {
                return $value;
            }
        }

        if (! empty($package->description)) {
            return strip_tags((string) $package->description);
        }

        $translations = $package->description_translations ?? [];
        $fallback = $translations['en'] ?? $translations['de'] ?? null;

        if ($fallback !== null) {
            $fallback = trim(strip_tags((string) $fallback));
            if ($fallback !== '') {
                return $fallback;
            }
        }

        $name = $package->name ?? $package->getNameForLocale('en');

        if ($name) {
            return sprintf('%s package', trim($name));
        }

        return sprintf('Package %s', $package->slug ?? $package->id);
    }

    protected function priceToMinorUnits(mixed $price): int
    {
        $value = is_string($price) ? (float) $price : (float) ($price ?? 0);

        return (int) round($value * 100);
    }
}
