<?php

namespace App\Insurance\Service;

use App\Insurance\Entity\TenantServiceCategorySetting;
use App\Insurance\Enum\ServiceCategory;
use App\Insurance\Repository\TenantServiceCategorySettingRepository;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Exception\AppException;

/**
 * The service kinds a tenant covers with insurance. One switch per kind, shared by
 * all of that tenant's insurances. A kind with no stored row counts as enabled.
 */
class TenantServiceCategoryService
{
    public function __construct(
        private readonly TenantServiceCategorySettingRepository $repo,
    ) {}

    /** @return list<string> enabled service_category values */
    public function enabledKeys(string $entityType, int $entityId): array
    {
        $stored = $this->repo->enabledMapFor($entityType, $entityId);

        return array_values(array_filter(
            ServiceCategory::values(),
            static fn(string $key) => $stored[$key] ?? true,
        ));
    }

    /**
     * Rows shaped for the settings UI — always every category, so the panel renders a
     * complete list without knowing which kinds exist.
     *
     * @return list<array{key: string, label: string, enabled: bool}>
     */
    public function settingsRows(string $entityType, int $entityId): array
    {
        $stored = $this->repo->enabledMapFor($entityType, $entityId);

        return array_map(static fn(ServiceCategory $c) => [
            'key'     => $c->value,
            'label'   => $c->label(),
            'enabled' => $stored[$c->value] ?? true,
        ], ServiceCategory::cases());
    }

    /**
     * The kind to bill with when nobody picked one: the single enabled kind, or null
     * when more than one is enabled (then the panel must ask).
     */
    public function defaultCategory(string $entityType, int $entityId): ?ServiceCategory
    {
        $enabled = $this->enabledKeys($entityType, $entityId);

        return count($enabled) === 1 ? ServiceCategory::from($enabled[0]) : null;
    }

    public function isEnabled(string $entityType, int $entityId, ServiceCategory $category): bool
    {
        return in_array($category->value, $this->enabledKeys($entityType, $entityId), true);
    }

    /**
     * @param list<array{key?: string, enabled?: mixed}> $rows
     * @throws AppException on an unknown category, or when the change would disable every kind
     */
    public function save(string $entityType, int $entityId, array $rows): void
    {
        $wanted = [];
        foreach ($rows as $row) {
            $category = ServiceCategory::tryFromValue(isset($row['key']) ? (string) $row['key'] : null);
            if ($category === null) {
                throw new AppException(
                    ErrorCodes::ERR_VALIDATION_001,
                    'نوع خدمت نامعتبر است: ' . implode('، ', ServiceCategory::values()),
                    422,
                    'service_categories',
                );
            }

            $wanted[$category->value] = (bool) ($row['enabled'] ?? false);
        }

        $resulting = array_filter(
            ServiceCategory::values(),
            fn(string $key) => $wanted[$key] ?? in_array($key, $this->enabledKeys($entityType, $entityId), true),
        );

        if ($resulting === []) {
            throw new AppException(
                ErrorCodes::ERR_VALIDATION_001,
                'حداقل یک نوع خدمت باید فعال باشد',
                422,
                'service_categories',
            );
        }

        foreach ($wanted as $key => $enabled) {
            $category = ServiceCategory::from($key);
            $entity   = $this->repo->findOneFor($entityType, $entityId, $category)
                ?? new TenantServiceCategorySetting($entityType, $entityId, $category);

            $this->repo->save($entity->setEnabled($enabled), false);
        }

        $this->repo->flush();
    }
}
